File Coverage

deps/libgit2/src/util.c
Criterion Covered Total %
statement 171 378 45.2
branch 113 296 38.1
condition n/a
subroutine n/a
pod n/a
total 284 674 42.1


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