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