util.c 16.7 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

#include "util.h"

10
#include "git2_util.h"
11

12
#ifdef GIT_WIN32
13
# include "win32/utf-conv.h"
14
# include "win32/w32_buffer.h"
15

16 17 18 19 20
# ifndef WIN32_LEAN_AND_MEAN
#  define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>

21
# ifdef GIT_QSORT_MSC
22 23
#  include <search.h>
# endif
24 25
#endif

26
#ifdef _MSC_VER
27 28 29
# include <Shlwapi.h>
#endif

30 31 32 33
#if defined(hpux) || defined(__hpux) || defined(_hpux)
# include <sys/pstat.h>
#endif

34 35
int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
{
36
	const char *p;
37 38
	int64_t n, nn, v;
	int c, ovfl, neg, ndig;
39 40 41 42 43 44 45 46 47 48

	p = nptr;
	neg = 0;
	n = 0;
	ndig = 0;
	ovfl = 0;

	/*
	 * White space
	 */
49 50 51 52 53
	while (nptr_len && git__isspace(*p))
		p++, nptr_len--;

	if (!nptr_len)
		goto Return;
54 55 56 57

	/*
	 * Sign
	 */
58 59
	if (*p == '-' || *p == '+') {
		if (*p == '-')
60
			neg = 1;
61 62 63 64 65 66
		p++;
		nptr_len--;
	}

	if (!nptr_len)
		goto Return;
67 68

	/*
69 70 71 72
	 * Automatically detect the base if none was given to us.
	 * Right now, we assume that a number starting with '0x'
	 * is hexadecimal and a number starting with '0' is
	 * octal.
73 74 75 76
	 */
	if (base == 0) {
		if (*p != '0')
			base = 10;
77 78 79
		else if (nptr_len > 2 && (p[1] == 'x' || p[1] == 'X'))
			base = 16;
		else
80
			base = 8;
81 82 83
	}

	if (base < 0 || 36 < base)
84 85 86
		goto Return;

	/*
87 88 89 90 91 92 93 94 95 96 97 98
	 * Skip prefix of '0x'-prefixed hexadecimal numbers. There is no
	 * need to do the same for '0'-prefixed octal numbers as a
	 * leading '0' does not have any impact. Also, if we skip a
	 * leading '0' in such a string, then we may end up with no
	 * digits left and produce an error later on which isn't one.
	 */
	if (base == 16 && nptr_len > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
		p += 2;
		nptr_len -= 2;
	}

	/*
99 100
	 * Non-empty sequence of digits
	 */
101
	for (; nptr_len > 0; p++,ndig++,nptr_len--) {
102 103 104 105 106 107 108 109 110 111
		c = *p;
		v = base;
		if ('0'<=c && c<='9')
			v = c - '0';
		else if ('a'<=c && c<='z')
			v = c - 'a' + 10;
		else if ('A'<=c && c<='Z')
			v = c - 'A' + 10;
		if (v >= base)
			break;
112
		v = neg ? -v : v;
113
		if (git__multiply_int64_overflow(&nn, n, base) || git__add_int64_overflow(&n, nn, v)) {
114
			ovfl = 1;
115 116 117
			/* Keep on iterating until the end of this number */
			continue;
		}
118 119 120
	}

Return:
121
	if (ndig == 0) {
122
		git_error_set(GIT_ERROR_INVALID, "failed to convert string to long: not a number");
123 124
		return -1;
	}
125 126 127 128

	if (endptr)
		*endptr = p;

129
	if (ovfl) {
130
		git_error_set(GIT_ERROR_INVALID, "failed to convert string to long: overflow error");
131 132
		return -1;
	}
133

134
	*result = n;
135
	return 0;
136 137
}

138 139
int git__strntol32(int32_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
{
140
	const char *tmp_endptr;
141 142
	int32_t tmp_int;
	int64_t tmp_long;
143
	int error;
144

145
	if ((error = git__strntol64(&tmp_long, nptr, nptr_len, &tmp_endptr, base)) < 0)
146 147 148
		return error;

	tmp_int = tmp_long & 0xFFFFFFFF;
149
	if (tmp_int != tmp_long) {
150
		int len = (int)(tmp_endptr - nptr);
151
		git_error_set(GIT_ERROR_INVALID, "failed to convert: '%.*s' is too large", len, nptr);
152 153
		return -1;
	}
154 155

	*result = tmp_int;
156 157
	if (endptr)
		*endptr = tmp_endptr;
158

159 160 161
	return error;
}

162 163
int git__strcasecmp(const char *a, const char *b)
{
164
	while (*a && *b && git__tolower(*a) == git__tolower(*b))
165
		++a, ++b;
166
	return ((unsigned char)git__tolower(*a) - (unsigned char)git__tolower(*b));
167 168
}

169 170 171 172 173
int git__strcasesort_cmp(const char *a, const char *b)
{
	int cmp = 0;

	while (*a && *b) {
Russell Belfer committed
174
		if (*a != *b) {
175
			if (git__tolower(*a) != git__tolower(*b))
Russell Belfer committed
176 177
				break;
			/* use case in sort order even if not in equivalence */
178
			if (!cmp)
Russell Belfer committed
179 180
				cmp = (int)(*(const uint8_t *)a) - (int)(*(const uint8_t *)b);
		}
181 182 183 184 185

		++a, ++b;
	}

	if (*a || *b)
186
		return (unsigned char)git__tolower(*a) - (unsigned char)git__tolower(*b);
187 188 189 190

	return cmp;
}

191 192
int git__strncasecmp(const char *a, const char *b, size_t sz)
{
Philip Kelley committed
193
	int al, bl;
194

Philip Kelley committed
195
	do {
196 197
		al = (unsigned char)git__tolower(*a);
		bl = (unsigned char)git__tolower(*b);
Philip Kelley committed
198 199
		++a, ++b;
	} while (--sz && al && al == bl);
200

Philip Kelley committed
201
	return al - bl;
202 203
}

204
void git__strntolower(char *str, size_t len)
205
{
206
	size_t i;
207 208

	for (i = 0; i < len; ++i) {
209
		str[i] = (char)git__tolower(str[i]);
210 211 212 213 214 215 216 217
	}
}

void git__strtolower(char *str)
{
	git__strntolower(str, strlen(str));
}

218
GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, bool icase)
219
{
220 221 222 223 224 225 226 227 228 229 230
	int s, p;

	while (str_n--) {
		s = (unsigned char)*str++;
		p = (unsigned char)*prefix++;

		if (icase) {
			s = git__tolower(s);
			p = git__tolower(p);
		}

231 232
		if (!p)
			return 0;
233 234

		if (s != p)
235 236
			return s - p;
	}
237 238

	return (0 - *prefix);
239 240
}

241
int git__prefixcmp(const char *str, const char *prefix)
242
{
romkatv committed
243 244 245 246 247 248 249 250 251 252 253 254
	unsigned char s, p;

	while (1) {
		p = *prefix++;
		s = *str++;

		if (!p)
			return 0;

		if (s != p)
			return s - p;
	}
255 256
}

257
int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
258
{
259 260
	return prefixcmp(str, str_n, prefix, false);
}
261

262 263 264 265
int git__prefixcmp_icase(const char *str, const char *prefix)
{
	return prefixcmp(str, SIZE_MAX, prefix, true);
}
266

267 268 269
int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
{
	return prefixcmp(str, str_n, prefix, true);
270 271
}

272 273 274 275 276 277 278 279
int git__suffixcmp(const char *str, const char *suffix)
{
	size_t a = strlen(str);
	size_t b = strlen(suffix);
	if (a < b)
		return -1;
	return strcmp(str + (a - b), suffix);
}
280

281
char *git__strtok(char **end, const char *sep)
282
{
283
	char *ptr = *end;
284

285 286
	while (*ptr && strchr(sep, *ptr))
		++ptr;
287

288 289 290
	if (*ptr) {
		char *start = ptr;
		*end = start + 1;
291

292 293
		while (**end && !strchr(sep, **end))
			++*end;
294

295 296 297 298 299 300 301 302 303
		if (**end) {
			**end = '\0';
			++*end;
		}

		return start;
	}

	return NULL;
304 305
}

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
/* Similar to strtok, but does not collapse repeated tokens. */
char *git__strsep(char **end, const char *sep)
{
	char *start = *end, *ptr = *end;

	while (*ptr && !strchr(sep, *ptr))
		++ptr;

	if (*ptr) {
		*end = ptr + 1;
		*ptr = '\0';

		return start;
	}

	return NULL;
}

324 325 326 327 328 329
size_t git__linenlen(const char *buffer, size_t buffer_len)
{
	char *nl = memchr(buffer, '\n', buffer_len);
	return nl ? (size_t)(nl - buffer) + 1 : buffer_len;
}

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
/*
 * Adapted Not So Naive algorithm from http://www-igm.univ-mlv.fr/~lecroq/string/
 */
const void * git__memmem(const void *haystack, size_t haystacklen,
			 const void *needle, size_t needlelen)
{
	const char *h, *n;
	size_t j, k, l;

	if (needlelen > haystacklen || !haystacklen || !needlelen)
		return NULL;

	h = (const char *) haystack,
	n = (const char *) needle;

	if (needlelen == 1)
		return memchr(haystack, *n, haystacklen);

	if (n[0] == n[1]) {
		k = 2;
		l = 1;
	} else {
		k = 1;
		l = 2;
	}

	j = 0;
	while (j <= haystacklen - needlelen) {
		if (n[1] != h[j + 1]) {
			j += k;
		} else {
			if (memcmp(n + 2, h + j + 2, needlelen - 2) == 0 &&
			    n[0] == h[j])
				return h + j;
			j += l;
		}
	}

	return NULL;
}

371 372 373 374 375 376 377 378 379 380 381
void git__hexdump(const char *buffer, size_t len)
{
	static const size_t LINE_WIDTH = 16;

	size_t line_count, last_line, i, j;
	const char *line;

	line_count = (len / LINE_WIDTH);
	last_line = (len % LINE_WIDTH);

	for (i = 0; i < line_count; ++i) {
382 383
		printf("%08" PRIxZ "  ", (i * LINE_WIDTH));

384
		line = buffer + (i * LINE_WIDTH);
385 386 387 388 389 390
		for (j = 0; j < LINE_WIDTH; ++j, ++line) {
			printf("%02x ", (unsigned char)*line & 0xFF);

			if (j == (LINE_WIDTH / 2))
				printf(" ");
		}
391

392
		printf(" |");
393 394 395 396 397

		line = buffer + (i * LINE_WIDTH);
		for (j = 0; j < LINE_WIDTH; ++j, ++line)
			printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');

398
		printf("|\n");
399 400 401
	}

	if (last_line > 0) {
402
		printf("%08" PRIxZ "  ", (line_count * LINE_WIDTH));
403 404

		line = buffer + (line_count * LINE_WIDTH);
405 406 407 408 409 410
		for (j = 0; j < last_line; ++j, ++line) {
			printf("%02x ", (unsigned char)*line & 0xFF);

			if (j == (LINE_WIDTH / 2))
				printf(" ");
		}
411

412 413
		if (j < (LINE_WIDTH / 2))
			printf(" ");
414
		for (j = 0; j < (LINE_WIDTH - last_line); ++j)
415
			printf("   ");
416

417
		printf(" |");
418 419 420 421 422

		line = buffer + (line_count * LINE_WIDTH);
		for (j = 0; j < last_line; ++j, ++line)
			printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');

423
		printf("|\n");
424 425 426 427
	}

	printf("\n");
}
428 429 430 431 432 433 434 435 436 437 438 439 440

#ifdef GIT_LEGACY_HASH
uint32_t git__hash(const void *key, int len, unsigned int seed)
{
	const uint32_t m = 0x5bd1e995;
	const int r = 24;
	uint32_t h = seed ^ len;

	const unsigned char *data = (const unsigned char *)key;

	while(len >= 4) {
		uint32_t k = *(uint32_t *)data;

441 442 443 444 445
		k *= m;
		k ^= k >> r;
		k *= m;

		h *= m;
446 447 448 449 450
		h ^= k;

		data += 4;
		len -= 4;
	}
451

452 453 454 455
	switch(len) {
	case 3: h ^= data[2] << 16;
	case 2: h ^= data[1] << 8;
	case 1: h ^= data[0];
Vicent Marti committed
456
			h *= m;
457 458 459 460 461 462 463
	};

	h ^= h >> 13;
	h *= m;
	h ^= h >> 15;

	return h;
464
}
465 466 467 468 469 470 471 472 473 474 475 476
#else
/*
	Cross-platform version of Murmurhash3
	http://code.google.com/p/smhasher/wiki/MurmurHash3
	by Austin Appleby (aappleby@gmail.com)

	This code is on the public domain.
*/
uint32_t git__hash(const void *key, int len, uint32_t seed)
{

#define MURMUR_BLOCK() {\
Vicent Marti committed
477 478 479 480 481 482 483
	k1 *= c1; \
	k1 = git__rotl(k1,11);\
	k1 *= c2;\
	h1 ^= k1;\
	h1 = h1*3 + 0x52dce729;\
	c1 = c1*5 + 0x7b7d159c;\
	c2 = c2*5 + 0x6bce6396;\
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
}

	const uint8_t *data = (const uint8_t*)key;
	const int nblocks = len / 4;

	const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
	const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);

	uint32_t h1 = 0x971e137b ^ seed;
	uint32_t k1;

	uint32_t c1 = 0x95543787;
	uint32_t c2 = 0x2ad7eb25;

	int i;

	for (i = -nblocks; i; i++) {
		k1 = blocks[i];
		MURMUR_BLOCK();
	}

	k1 = 0;

	switch(len & 3) {
	case 3: k1 ^= tail[2] << 16;
509
		/* fall through */
510
	case 2: k1 ^= tail[1] << 8;
511
		/* fall through */
512
	case 1: k1 ^= tail[0];
513
		MURMUR_BLOCK();
514 515 516 517 518 519 520 521 522 523
	}

	h1 ^= len;
	h1 ^= h1 >> 16;
	h1 *= 0x85ebca6b;
	h1 ^= h1 >> 13;
	h1 *= 0xc2b2ae35;
	h1 ^= h1 >> 16;

	return h1;
524
}
525
#endif
526

527 528 529 530 531
/**
 * A modified `bsearch` from the BSD glibc.
 *
 * Copyright (c) 1990 Regents of the University of California.
 * All rights reserved.
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. [rescinded 22 July 1999]
 * 4. Neither the name of the University nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
556
 */
557 558 559 560 561 562
int git__bsearch(
	void **array,
	size_t array_len,
	const void *key,
	int (*compare)(const void *, const void *),
	size_t *position)
563
{
564
	size_t lim;
565
	int cmp = -1;
566 567
	void **part, **base = array;

568
	for (lim = array_len; lim != 0; lim >>= 1) {
569 570 571
		part = base + (lim >> 1);
		cmp = (*compare)(key, *part);
		if (cmp == 0) {
572 573 574 575
			base = part;
			break;
		}
		if (cmp > 0) { /* key > p; take right partition */
576 577 578 579 580
			base = part + 1;
			lim--;
		} /* else take left partition */
	}

581 582
	if (position)
		*position = (base - array);
583

584
	return (cmp == 0) ? 0 : GIT_ENOTFOUND;
585 586 587 588 589 590 591 592 593 594
}

int git__bsearch_r(
	void **array,
	size_t array_len,
	const void *key,
	int (*compare_r)(const void *, const void *, void *),
	void *payload,
	size_t *position)
{
595
	size_t lim;
596 597 598
	int cmp = -1;
	void **part, **base = array;

599
	for (lim = array_len; lim != 0; lim >>= 1) {
600 601 602 603 604 605 606 607 608 609 610 611 612 613
		part = base + (lim >> 1);
		cmp = (*compare_r)(key, *part, payload);
		if (cmp == 0) {
			base = part;
			break;
		}
		if (cmp > 0) { /* key > p; take right partition */
			base = part + 1;
			lim--;
		} /* else take left partition */
	}

	if (position)
		*position = (base - array);
614

615
	return (cmp == 0) ? 0 : GIT_ENOTFOUND;
616 617
}

618 619
/**
 * A strcmp wrapper
620
 *
621 622 623 624 625
 * We don't want direct pointers to the CRT on Windows, we may
 * get stdcall conflicts.
 */
int git__strcmp_cb(const void *a, const void *b)
{
626 627
	return strcmp((const char *)a, (const char *)b);
}
628

629 630 631
int git__strcasecmp_cb(const void *a, const void *b)
{
	return strcasecmp((const char *)a, (const char *)b);
632
}
633 634 635 636

int git__parse_bool(int *out, const char *value)
{
	/* A missing value means true */
637 638
	if (value == NULL ||
		!strcasecmp(value, "true") ||
639 640 641 642 643 644 645
		!strcasecmp(value, "yes") ||
		!strcasecmp(value, "on")) {
		*out = 1;
		return 0;
	}
	if (!strcasecmp(value, "false") ||
		!strcasecmp(value, "no") ||
646 647
		!strcasecmp(value, "off") ||
		value[0] == '\0') {
648 649 650 651 652 653
		*out = 0;
		return 0;
	}

	return -1;
}
654 655 656 657 658

size_t git__unescape(char *str)
{
	char *scan, *pos = str;

659 660 661
	if (!str)
		return 0;

662 663 664 665 666 667 668 669 670 671 672 673 674
	for (scan = str; *scan; pos++, scan++) {
		if (*scan == '\\' && *(scan + 1) != '\0')
			scan++; /* skip '\' but include next char */
		if (pos != scan)
			*pos = *scan;
	}

	if (pos != scan) {
		*pos = '\0';
	}

	return (pos - str);
}
675

676
#if defined(GIT_QSORT_MSC) || defined(GIT_QSORT_BSD)
677
typedef struct {
678
	git__sort_r_cmp cmp;
679 680 681
	void *payload;
} git__qsort_r_glue;

682
static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp(
683 684 685 686 687 688 689
	void *payload, const void *a, const void *b)
{
	git__qsort_r_glue *glue = payload;
	return glue->cmp(a, b, glue->payload);
}
#endif

690

691 692 693 694 695
#if !defined(GIT_QSORT_BSD) && \
    !defined(GIT_QSORT_GNU) && \
    !defined(GIT_QSORT_C11) && \
    !defined(GIT_QSORT_MSC)

696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
static void swap(uint8_t *a, uint8_t *b, size_t elsize)
{
	char tmp[256];

	while (elsize) {
		size_t n = elsize < sizeof(tmp) ? elsize : sizeof(tmp);
		memcpy(tmp, a + elsize - n, n);
		memcpy(a + elsize - n, b + elsize - n, n);
		memcpy(b + elsize - n, tmp, n);
		elsize -= n;
	}
}

static void insertsort(
	void *els, size_t nel, size_t elsize,
	git__sort_r_cmp cmp, void *payload)
{
	uint8_t *base = els;
	uint8_t *end = base + nel * elsize;
	uint8_t *i, *j;

	for (i = base + elsize; i < end; i += elsize)
		for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize)
			swap(j, j - elsize, elsize);
}
721

722
#endif
723

724
void git__qsort_r(
725
	void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload)
726
{
727
#if defined(GIT_QSORT_GNU)
728
	qsort_r(els, nel, elsize, cmp, payload);
729
#elif defined(GIT_QSORT_C11)
730
	qsort_s(els, nel, elsize, cmp, payload);
731
#elif defined(GIT_QSORT_BSD)
732 733
	git__qsort_r_glue glue = { cmp, payload };
	qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp);
734
#elif defined(GIT_QSORT_MSC)
735 736 737
	git__qsort_r_glue glue = { cmp, payload };
	qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
#else
738
	insertsort(els, nel, elsize, cmp, payload);
739
#endif
740 741
}

742
#ifdef GIT_WIN32
743
int git__getenv(git_str *out, const char *name)
744 745 746 747 748
{
	wchar_t *wide_name = NULL, *wide_value = NULL;
	DWORD value_len;
	int error = -1;

749
	git_str_clear(out);
750

751
	if (git_utf8_to_16_alloc(&wide_name, name) < 0)
752 753 754 755
		return -1;

	if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) {
		wide_value = git__malloc(value_len * sizeof(wchar_t));
756
		GIT_ERROR_CHECK_ALLOC(wide_value);
757 758 759 760 761

		value_len = GetEnvironmentVariableW(wide_name, wide_value, value_len);
	}

	if (value_len)
762
		error = git_str_put_w(out, wide_value, value_len);
763
	else if (GetLastError() == ERROR_SUCCESS || GetLastError() == ERROR_ENVVAR_NOT_FOUND)
764 765
		error = GIT_ENOTFOUND;
	else
766
		git_error_set(GIT_ERROR_OS, "could not read environment variable '%s'", name);
767 768 769 770 771 772

	git__free(wide_name);
	git__free(wide_value);
	return error;
}
#else
773
int git__getenv(git_str *out, const char *name)
774 775 776
{
	const char *val = getenv(name);

777
	git_str_clear(out);
778 779 780 781

	if (!val)
		return GIT_ENOTFOUND;

782
	return git_str_puts(out, val);
783 784
}
#endif
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824

/*
 * By doing this in two steps we can at least get
 * the function to be somewhat coherent, even
 * with this disgusting nest of #ifdefs.
 */
#ifndef _SC_NPROCESSORS_ONLN
#	ifdef _SC_NPROC_ONLN
#		define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
#	elif defined _SC_CRAY_NCPU
#		define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
#	endif
#endif

int git__online_cpus(void)
{
#ifdef _SC_NPROCESSORS_ONLN
	long ncpus;
#endif

#ifdef _WIN32
	SYSTEM_INFO info;
	GetSystemInfo(&info);

	if ((int)info.dwNumberOfProcessors > 0)
		return (int)info.dwNumberOfProcessors;
#elif defined(hpux) || defined(__hpux) || defined(_hpux)
	struct pst_dynamic psd;

	if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
		return (int)psd.psd_proc_cnt;
#endif

#ifdef _SC_NPROCESSORS_ONLN
	if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
		return (int)ncpus;
#endif

	return 1;
}