Coverage Report

Created: 2026-04-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libgit2/src/util/util.c
Line
Count
Source
1
/*
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
3
 *
4
 * This file is part of libgit2, distributed under the GNU GPL v2 with
5
 * a Linking Exception. For full terms see the included COPYING file.
6
 */
7
8
#include "util.h"
9
10
#include "git2_util.h"
11
12
#ifdef GIT_WIN32
13
# include "win32/utf-conv.h"
14
# include "win32/w32_buffer.h"
15
16
# ifndef WIN32_LEAN_AND_MEAN
17
#  define WIN32_LEAN_AND_MEAN
18
# endif
19
# include <windows.h>
20
21
# ifdef GIT_QSORT_MSC
22
#  include <search.h>
23
# endif
24
#endif
25
26
#ifdef _MSC_VER
27
# include <Shlwapi.h>
28
#endif
29
30
#if defined(hpux) || defined(__hpux) || defined(_hpux)
31
# include <sys/pstat.h>
32
#endif
33
34
int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
35
3.14k
{
36
3.14k
  const char *p;
37
3.14k
  int64_t n, nn, v;
38
3.14k
  int c, ovfl, neg, ndig;
39
40
3.14k
  p = nptr;
41
3.14k
  neg = 0;
42
3.14k
  n = 0;
43
3.14k
  ndig = 0;
44
3.14k
  ovfl = 0;
45
46
  /*
47
   * White space
48
   */
49
3.36k
  while (nptr_len && git__isspace(*p))
50
214
    p++, nptr_len--;
51
52
3.14k
  if (!nptr_len)
53
10
    goto Return;
54
55
  /*
56
   * Sign
57
   */
58
3.13k
  if (*p == '-' || *p == '+') {
59
146
    if (*p == '-')
60
89
      neg = 1;
61
146
    p++;
62
146
    nptr_len--;
63
146
  }
64
65
3.13k
  if (!nptr_len)
66
3
    goto Return;
67
68
  /*
69
   * Automatically detect the base if none was given to us.
70
   * Right now, we assume that a number starting with '0x'
71
   * is hexadecimal and a number starting with '0' is
72
   * octal.
73
   */
74
3.13k
  if (base == 0) {
75
2
    if (*p != '0')
76
0
      base = 10;
77
2
    else if (nptr_len > 2 && (p[1] == 'x' || p[1] == 'X'))
78
0
      base = 16;
79
2
    else
80
2
      base = 8;
81
2
  }
82
83
3.13k
  if (base < 0 || 36 < base)
84
0
    goto Return;
85
86
  /*
87
   * Skip prefix of '0x'-prefixed hexadecimal numbers. There is no
88
   * need to do the same for '0'-prefixed octal numbers as a
89
   * leading '0' does not have any impact. Also, if we skip a
90
   * leading '0' in such a string, then we may end up with no
91
   * digits left and produce an error later on which isn't one.
92
   */
93
3.13k
  if (base == 16 && nptr_len > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
94
0
    p += 2;
95
0
    nptr_len -= 2;
96
0
  }
97
98
  /*
99
   * Non-empty sequence of digits
100
   */
101
131k
  for (; nptr_len > 0; p++,ndig++,nptr_len--) {
102
131k
    c = *p;
103
131k
    v = base;
104
131k
    if ('0'<=c && c<='9')
105
128k
      v = c - '0';
106
2.81k
    else if ('a'<=c && c<='z')
107
306
      v = c - 'a' + 10;
108
2.51k
    else if ('A'<=c && c<='Z')
109
300
      v = c - 'A' + 10;
110
131k
    if (v >= base)
111
2.81k
      break;
112
128k
    v = neg ? -v : v;
113
128k
    if (git__multiply_int64_overflow(&nn, n, base) || git__add_int64_overflow(&n, nn, v)) {
114
63.2k
      ovfl = 1;
115
      /* Keep on iterating until the end of this number */
116
63.2k
      continue;
117
63.2k
    }
118
128k
  }
119
120
3.14k
Return:
121
3.14k
  if (ndig == 0) {
122
786
    git_error_set(GIT_ERROR_INVALID, "failed to convert string to long: not a number");
123
786
    return -1;
124
786
  }
125
126
2.36k
  if (endptr)
127
2.36k
    *endptr = p;
128
129
2.36k
  if (ovfl) {
130
139
    git_error_set(GIT_ERROR_INVALID, "failed to convert string to long: overflow error");
131
139
    return -1;
132
139
  }
133
134
2.22k
  *result = n;
135
2.22k
  return 0;
136
2.36k
}
137
138
int git__strntol32(int32_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
139
3.14k
{
140
3.14k
  const char *tmp_endptr;
141
3.14k
  int32_t tmp_int;
142
3.14k
  int64_t tmp_long;
143
3.14k
  int error;
144
145
3.14k
  if ((error = git__strntol64(&tmp_long, nptr, nptr_len, &tmp_endptr, base)) < 0)
146
925
    return error;
147
148
2.22k
  tmp_int = tmp_long & 0xFFFFFFFF;
149
2.22k
  if (tmp_int != tmp_long) {
150
369
    int len = (int)(tmp_endptr - nptr);
151
369
    git_error_set(GIT_ERROR_INVALID, "failed to convert: '%.*s' is too large", len, nptr);
152
369
    return -1;
153
369
  }
154
155
1.85k
  *result = tmp_int;
156
1.85k
  if (endptr)
157
1.85k
    *endptr = tmp_endptr;
158
159
1.85k
  return error;
160
2.22k
}
161
162
int git__strcasecmp(const char *a, const char *b)
163
0
{
164
0
  while (*a && *b && git__tolower(*a) == git__tolower(*b))
165
0
    ++a, ++b;
166
0
  return ((unsigned char)git__tolower(*a) - (unsigned char)git__tolower(*b));
167
0
}
168
169
int git__strcasesort_cmp(const char *a, const char *b)
170
0
{
171
0
  int cmp = 0;
172
173
0
  while (*a && *b) {
174
0
    if (*a != *b) {
175
0
      if (git__tolower(*a) != git__tolower(*b))
176
0
        break;
177
      /* use case in sort order even if not in equivalence */
178
0
      if (!cmp)
179
0
        cmp = (int)(*(const uint8_t *)a) - (int)(*(const uint8_t *)b);
180
0
    }
181
182
0
    ++a, ++b;
183
0
  }
184
185
0
  if (*a || *b)
186
0
    return (unsigned char)git__tolower(*a) - (unsigned char)git__tolower(*b);
187
188
0
  return cmp;
189
0
}
190
191
int git__strncasecmp(const char *a, const char *b, size_t sz)
192
0
{
193
0
  int al, bl;
194
195
0
  do {
196
0
    al = (unsigned char)git__tolower(*a);
197
0
    bl = (unsigned char)git__tolower(*b);
198
0
    ++a, ++b;
199
0
  } while (--sz && al && al == bl);
200
201
0
  return al - bl;
202
0
}
203
204
void git__strntolower(char *str, size_t len)
205
0
{
206
0
  size_t i;
207
208
0
  for (i = 0; i < len; ++i) {
209
0
    str[i] = (char)git__tolower(str[i]);
210
0
  }
211
0
}
212
213
void git__strtolower(char *str)
214
0
{
215
0
  git__strntolower(str, strlen(str));
216
0
}
217
218
GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, bool icase)
219
0
{
220
0
  int s, p;
221
222
0
  while (str_n--) {
223
0
    s = (unsigned char)*str++;
224
0
    p = (unsigned char)*prefix++;
225
226
0
    if (icase) {
227
0
      s = git__tolower(s);
228
0
      p = git__tolower(p);
229
0
    }
230
231
0
    if (!p)
232
0
      return 0;
233
234
0
    if (s != p)
235
0
      return s - p;
236
0
  }
237
238
0
  return (0 - *prefix);
239
0
}
240
241
int git__prefixcmp(const char *str, const char *prefix)
242
33.3k
{
243
33.3k
  unsigned char s, p;
244
245
189k
  while (1) {
246
189k
    p = *prefix++;
247
189k
    s = *str++;
248
249
189k
    if (!p)
250
14.0k
      return 0;
251
252
175k
    if (s != p)
253
19.2k
      return s - p;
254
175k
  }
255
33.3k
}
256
257
int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
258
0
{
259
0
  return prefixcmp(str, str_n, prefix, false);
260
0
}
261
262
int git__prefixcmp_icase(const char *str, const char *prefix)
263
0
{
264
0
  return prefixcmp(str, SIZE_MAX, prefix, true);
265
0
}
266
267
int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
268
0
{
269
0
  return prefixcmp(str, str_n, prefix, true);
270
0
}
271
272
static int suffixcmp(const char *str, const char *suffix, bool icase)
273
2
{
274
2
  size_t a = strlen(str);
275
2
  size_t b = strlen(suffix);
276
277
2
  if (a < b)
278
0
    return -1;
279
280
2
  return icase ? strcasecmp(str + (a - b), suffix) :
281
2
                 strcmp(str + (a - b), suffix);
282
2
}
283
284
int git__suffixcmp(const char *str, const char *suffix)
285
2
{
286
2
  return suffixcmp(str, suffix, false);
287
2
}
288
289
int git__suffixcmp_icase(const char *str, const char *suffix)
290
0
{
291
0
  return suffixcmp(str, suffix, true);
292
0
}
293
294
char *git__strtok(char **end, const char *sep)
295
0
{
296
0
  char *ptr = *end;
297
298
0
  while (*ptr && strchr(sep, *ptr))
299
0
    ++ptr;
300
301
0
  if (*ptr) {
302
0
    char *start = ptr;
303
0
    *end = start + 1;
304
305
0
    while (**end && !strchr(sep, **end))
306
0
      ++*end;
307
308
0
    if (**end) {
309
0
      **end = '\0';
310
0
      ++*end;
311
0
    }
312
313
0
    return start;
314
0
  }
315
316
0
  return NULL;
317
0
}
318
319
/* Similar to strtok, but does not collapse repeated tokens. */
320
char *git__strsep(char **end, const char *sep)
321
0
{
322
0
  char *start = *end, *ptr = *end;
323
324
0
  while (*ptr && !strchr(sep, *ptr))
325
0
    ++ptr;
326
327
0
  if (*ptr) {
328
0
    *end = ptr + 1;
329
0
    *ptr = '\0';
330
331
0
    return start;
332
0
  }
333
334
0
  return NULL;
335
0
}
336
337
size_t git__linenlen(const char *buffer, size_t buffer_len)
338
250
{
339
250
  const char *nl = memchr(buffer, '\n', buffer_len);
340
250
  return nl ? (size_t)(nl - buffer) + 1 : buffer_len;
341
250
}
342
343
/*
344
 * Adapted Not So Naive algorithm from http://www-igm.univ-mlv.fr/~lecroq/string/
345
 */
346
const void * git__memmem(const void *haystack, size_t haystacklen,
347
       const void *needle, size_t needlelen)
348
0
{
349
0
  const char *h, *n;
350
0
  size_t j, k, l;
351
352
0
  if (needlelen > haystacklen || !haystacklen || !needlelen)
353
0
    return NULL;
354
355
0
  h = (const char *) haystack,
356
0
  n = (const char *) needle;
357
358
0
  if (needlelen == 1)
359
0
    return memchr(haystack, *n, haystacklen);
360
361
0
  if (n[0] == n[1]) {
362
0
    k = 2;
363
0
    l = 1;
364
0
  } else {
365
0
    k = 1;
366
0
    l = 2;
367
0
  }
368
369
0
  j = 0;
370
0
  while (j <= haystacklen - needlelen) {
371
0
    if (n[1] != h[j + 1]) {
372
0
      j += k;
373
0
    } else {
374
0
      if (memcmp(n + 2, h + j + 2, needlelen - 2) == 0 &&
375
0
          n[0] == h[j])
376
0
        return h + j;
377
0
      j += l;
378
0
    }
379
0
  }
380
381
0
  return NULL;
382
0
}
383
384
void git__hexdump(const char *buffer, size_t len)
385
0
{
386
0
  static const size_t LINE_WIDTH = 16;
387
388
0
  size_t line_count, last_line, i, j;
389
0
  const char *line;
390
391
0
  line_count = (len / LINE_WIDTH);
392
0
  last_line = (len % LINE_WIDTH);
393
394
0
  for (i = 0; i < line_count; ++i) {
395
0
    printf("%08" PRIxZ "  ", (i * LINE_WIDTH));
396
397
0
    line = buffer + (i * LINE_WIDTH);
398
0
    for (j = 0; j < LINE_WIDTH; ++j, ++line) {
399
0
      printf("%02x ", (unsigned char)*line & 0xFF);
400
401
0
      if (j == (LINE_WIDTH / 2))
402
0
        printf(" ");
403
0
    }
404
405
0
    printf(" |");
406
407
0
    line = buffer + (i * LINE_WIDTH);
408
0
    for (j = 0; j < LINE_WIDTH; ++j, ++line)
409
0
      printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
410
411
0
    printf("|\n");
412
0
  }
413
414
0
  if (last_line > 0) {
415
0
    printf("%08" PRIxZ "  ", (line_count * LINE_WIDTH));
416
417
0
    line = buffer + (line_count * LINE_WIDTH);
418
0
    for (j = 0; j < last_line; ++j, ++line) {
419
0
      printf("%02x ", (unsigned char)*line & 0xFF);
420
421
0
      if (j == (LINE_WIDTH / 2))
422
0
        printf(" ");
423
0
    }
424
425
0
    if (j < (LINE_WIDTH / 2))
426
0
      printf(" ");
427
0
    for (j = 0; j < (LINE_WIDTH - last_line); ++j)
428
0
      printf("   ");
429
430
0
    printf(" |");
431
432
0
    line = buffer + (line_count * LINE_WIDTH);
433
0
    for (j = 0; j < last_line; ++j, ++line)
434
0
      printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
435
436
0
    printf("|\n");
437
0
  }
438
439
0
  printf("\n");
440
0
}
441
442
#ifdef GIT_LEGACY_HASH
443
uint32_t git__hash(const void *key, int len, unsigned int seed)
444
{
445
  const uint32_t m = 0x5bd1e995;
446
  const int r = 24;
447
  uint32_t h = seed ^ len;
448
449
  const unsigned char *data = (const unsigned char *)key;
450
451
  while(len >= 4) {
452
    uint32_t k = *(uint32_t *)data;
453
454
    k *= m;
455
    k ^= k >> r;
456
    k *= m;
457
458
    h *= m;
459
    h ^= k;
460
461
    data += 4;
462
    len -= 4;
463
  }
464
465
  switch(len) {
466
  case 3: h ^= data[2] << 16;
467
  case 2: h ^= data[1] << 8;
468
  case 1: h ^= data[0];
469
      h *= m;
470
  };
471
472
  h ^= h >> 13;
473
  h *= m;
474
  h ^= h >> 15;
475
476
  return h;
477
}
478
#else
479
/*
480
  Cross-platform version of Murmurhash3
481
  http://code.google.com/p/smhasher/wiki/MurmurHash3
482
  by Austin Appleby (aappleby@gmail.com)
483
484
  This code is on the public domain.
485
*/
486
uint32_t git__hash(const void *key, int len, uint32_t seed)
487
0
{
488
489
0
#define MURMUR_BLOCK() {\
490
0
  k1 *= c1; \
491
0
  k1 = git__rotl(k1,11);\
492
0
  k1 *= c2;\
493
0
  h1 ^= k1;\
494
0
  h1 = h1*3 + 0x52dce729;\
495
0
  c1 = c1*5 + 0x7b7d159c;\
496
0
  c2 = c2*5 + 0x6bce6396;\
497
0
}
498
499
0
  const uint8_t *data = (const uint8_t*)key;
500
0
  const int nblocks = len / 4;
501
502
0
  const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
503
0
  const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
504
505
0
  uint32_t h1 = 0x971e137b ^ seed;
506
0
  uint32_t k1;
507
508
0
  uint32_t c1 = 0x95543787;
509
0
  uint32_t c2 = 0x2ad7eb25;
510
511
0
  int i;
512
513
0
  for (i = -nblocks; i; i++) {
514
0
    k1 = blocks[i];
515
0
    MURMUR_BLOCK();
516
0
  }
517
518
0
  k1 = 0;
519
520
0
  switch(len & 3) {
521
0
  case 3: k1 ^= tail[2] << 16;
522
    /* fall through */
523
0
  case 2: k1 ^= tail[1] << 8;
524
    /* fall through */
525
0
  case 1: k1 ^= tail[0];
526
0
    MURMUR_BLOCK();
527
0
  }
528
529
0
  h1 ^= len;
530
0
  h1 ^= h1 >> 16;
531
0
  h1 *= 0x85ebca6b;
532
0
  h1 ^= h1 >> 13;
533
0
  h1 *= 0xc2b2ae35;
534
0
  h1 ^= h1 >> 16;
535
536
0
  return h1;
537
0
}
538
#endif
539
540
/**
541
 * A modified `bsearch` from the BSD glibc.
542
 *
543
 * Copyright (c) 1990 Regents of the University of California.
544
 * All rights reserved.
545
 * Redistribution and use in source and binary forms, with or without
546
 * modification, are permitted provided that the following conditions
547
 * are met:
548
 * 1. Redistributions of source code must retain the above copyright
549
 * notice, this list of conditions and the following disclaimer.
550
 * 2. Redistributions in binary form must reproduce the above copyright
551
 * notice, this list of conditions and the following disclaimer in the
552
 * documentation and/or other materials provided with the distribution.
553
 * 3. [rescinded 22 July 1999]
554
 * 4. Neither the name of the University nor the names of its contributors
555
 * may be used to endorse or promote products derived from this software
556
 * without specific prior written permission.
557
 *
558
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
559
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
560
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
561
 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
562
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
563
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
564
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
565
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
566
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
567
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
568
 * SUCH DAMAGE.
569
 */
570
int git__bsearch(
571
  void **array,
572
  size_t array_len,
573
  const void *key,
574
  int (*compare)(const void *, const void *),
575
  size_t *position)
576
34
{
577
34
  size_t lim;
578
34
  int cmp = -1;
579
34
  void **part, **base = array;
580
581
48
  for (lim = array_len; lim != 0; lim >>= 1) {
582
14
    part = base + (lim >> 1);
583
14
    cmp = (*compare)(key, *part);
584
14
    if (cmp == 0) {
585
0
      base = part;
586
0
      break;
587
0
    }
588
14
    if (cmp > 0) { /* key > p; take right partition */
589
10
      base = part + 1;
590
10
      lim--;
591
10
    } /* else take left partition */
592
14
  }
593
594
34
  if (position)
595
34
    *position = (base - array);
596
597
34
  return (cmp == 0) ? 0 : GIT_ENOTFOUND;
598
34
}
599
600
int git__bsearch_r(
601
  void **array,
602
  size_t array_len,
603
  const void *key,
604
  int (*compare_r)(const void *, const void *, void *),
605
  void *payload,
606
  size_t *position)
607
0
{
608
0
  size_t lim;
609
0
  int cmp = -1;
610
0
  void **part, **base = array;
611
612
0
  for (lim = array_len; lim != 0; lim >>= 1) {
613
0
    part = base + (lim >> 1);
614
0
    cmp = (*compare_r)(key, *part, payload);
615
0
    if (cmp == 0) {
616
0
      base = part;
617
0
      break;
618
0
    }
619
0
    if (cmp > 0) { /* key > p; take right partition */
620
0
      base = part + 1;
621
0
      lim--;
622
0
    } /* else take left partition */
623
0
  }
624
625
0
  if (position)
626
0
    *position = (base - array);
627
628
0
  return (cmp == 0) ? 0 : GIT_ENOTFOUND;
629
0
}
630
631
/**
632
 * A strcmp wrapper
633
 *
634
 * We don't want direct pointers to the CRT on Windows, we may
635
 * get stdcall conflicts.
636
 */
637
int git__strcmp_cb(const void *a, const void *b)
638
0
{
639
0
  return git__strcmp((const char *)a, (const char *)b);
640
0
}
641
642
int git__strcasecmp_cb(const void *a, const void *b)
643
0
{
644
0
  return git__strcasecmp((const char *)a, (const char *)b);
645
0
}
646
647
int git__parse_bool(int *out, const char *value)
648
2
{
649
  /* A missing value means true */
650
2
  if (value == NULL ||
651
2
    !strcasecmp(value, "true") ||
652
0
    !strcasecmp(value, "yes") ||
653
2
    !strcasecmp(value, "on")) {
654
2
    *out = 1;
655
2
    return 0;
656
2
  }
657
0
  if (!strcasecmp(value, "false") ||
658
0
    !strcasecmp(value, "no") ||
659
0
    !strcasecmp(value, "off") ||
660
0
    value[0] == '\0') {
661
0
    *out = 0;
662
0
    return 0;
663
0
  }
664
665
0
  return -1;
666
0
}
667
668
size_t git__unescape(char *str)
669
0
{
670
0
  char *scan, *pos = str;
671
672
0
  if (!str)
673
0
    return 0;
674
675
0
  for (scan = str; *scan; pos++, scan++) {
676
0
    if (*scan == '\\' && *(scan + 1) != '\0')
677
0
      scan++; /* skip '\' but include next char */
678
0
    if (pos != scan)
679
0
      *pos = *scan;
680
0
  }
681
682
0
  if (pos != scan) {
683
0
    *pos = '\0';
684
0
  }
685
686
0
  return (pos - str);
687
0
}
688
689
#if defined(GIT_QSORT_MSC) || defined(GIT_QSORT_BSD)
690
typedef struct {
691
  git__sort_r_cmp cmp;
692
  void *payload;
693
} git__qsort_r_glue;
694
695
static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp(
696
  void *payload, const void *a, const void *b)
697
{
698
  git__qsort_r_glue *glue = payload;
699
  return glue->cmp(a, b, glue->payload);
700
}
701
#endif
702
703
704
#if !defined(GIT_QSORT_BSD) && \
705
    !defined(GIT_QSORT_GNU) && \
706
    !defined(GIT_QSORT_C11) && \
707
    !defined(GIT_QSORT_MSC)
708
709
static void swap(uint8_t *a, uint8_t *b, size_t elsize)
710
{
711
  char tmp[256];
712
713
  while (elsize) {
714
    size_t n = elsize < sizeof(tmp) ? elsize : sizeof(tmp);
715
    memcpy(tmp, a + elsize - n, n);
716
    memcpy(a + elsize - n, b + elsize - n, n);
717
    memcpy(b + elsize - n, tmp, n);
718
    elsize -= n;
719
  }
720
}
721
722
static void insertsort(
723
  void *els, size_t nel, size_t elsize,
724
  git__sort_r_cmp cmp, void *payload)
725
{
726
  uint8_t *base = els;
727
  uint8_t *end = base + nel * elsize;
728
  uint8_t *i, *j;
729
730
  for (i = base + elsize; i < end; i += elsize)
731
    for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize)
732
      swap(j, j - elsize, elsize);
733
}
734
735
#endif
736
737
void git__qsort_r(
738
  void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload)
739
0
{
740
0
#if defined(GIT_QSORT_GNU)
741
0
  qsort_r(els, nel, elsize, cmp, payload);
742
#elif defined(GIT_QSORT_C11)
743
  qsort_s(els, nel, elsize, cmp, payload);
744
#elif defined(GIT_QSORT_BSD)
745
  git__qsort_r_glue glue = { cmp, payload };
746
  qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp);
747
#elif defined(GIT_QSORT_MSC)
748
  git__qsort_r_glue glue = { cmp, payload };
749
  qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
750
#else
751
  insertsort(els, nel, elsize, cmp, payload);
752
#endif
753
0
}
754
755
#ifdef GIT_WIN32
756
int git__getenv(git_str *out, const char *name)
757
{
758
  wchar_t *wide_name = NULL, *wide_value = NULL;
759
  DWORD value_len;
760
  int error = -1;
761
762
  git_str_clear(out);
763
764
  if (git_utf8_to_16_alloc(&wide_name, name) < 0)
765
    return -1;
766
767
  if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) {
768
    wide_value = git__malloc(value_len * sizeof(wchar_t));
769
    GIT_ERROR_CHECK_ALLOC(wide_value);
770
771
    value_len = GetEnvironmentVariableW(wide_name, wide_value, value_len);
772
  }
773
774
  if (value_len)
775
    error = git_str_put_w(out, wide_value, value_len);
776
  else if (GetLastError() == ERROR_SUCCESS || GetLastError() == ERROR_ENVVAR_NOT_FOUND)
777
    error = GIT_ENOTFOUND;
778
  else
779
    git_error_set(GIT_ERROR_OS, "could not read environment variable '%s'", name);
780
781
  git__free(wide_name);
782
  git__free(wide_value);
783
  return error;
784
}
785
#else
786
int git__getenv(git_str *out, const char *name)
787
10
{
788
10
  const char *val = getenv(name);
789
790
10
  git_str_clear(out);
791
792
10
  if (!val)
793
4
    return GIT_ENOTFOUND;
794
795
6
  return git_str_puts(out, val);
796
10
}
797
#endif
798
799
/*
800
 * By doing this in two steps we can at least get
801
 * the function to be somewhat coherent, even
802
 * with this disgusting nest of #ifdefs.
803
 */
804
#ifndef _SC_NPROCESSORS_ONLN
805
# ifdef _SC_NPROC_ONLN
806
#   define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
807
# elif defined _SC_CRAY_NCPU
808
#   define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
809
# endif
810
#endif
811
812
int git__online_cpus(void)
813
0
{
814
0
#ifdef _SC_NPROCESSORS_ONLN
815
0
  long ncpus;
816
0
#endif
817
818
#ifdef _WIN32
819
  SYSTEM_INFO info;
820
  GetSystemInfo(&info);
821
822
  if ((int)info.dwNumberOfProcessors > 0)
823
    return (int)info.dwNumberOfProcessors;
824
#elif defined(hpux) || defined(__hpux) || defined(_hpux)
825
  struct pst_dynamic psd;
826
827
  if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
828
    return (int)psd.psd_proc_cnt;
829
#endif
830
831
0
#ifdef _SC_NPROCESSORS_ONLN
832
0
  if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
833
0
    return (int)ncpus;
834
0
#endif
835
836
0
  return 1;
837
0
}