File Coverage

deps/libgit2/src/util.c
Criterion Covered Total %
statement 165 362 45.5
branch 110 284 38.7
condition n/a
subroutine n/a
pod n/a
total 275 646 42.5


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