]> git.proxmox.com Git - libgit2.git/blob - src/util.c
New upstream version 1.1.0+dfsg.1
[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 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 p = nptr;
32 neg = 0;
33 n = 0;
34 ndig = 0;
35 ovfl = 0;
36
37 /*
38 * White space
39 */
40 while (nptr_len && git__isspace(*p))
41 p++, nptr_len--;
42
43 if (!nptr_len)
44 goto Return;
45
46 /*
47 * Sign
48 */
49 if (*p == '-' || *p == '+') {
50 if (*p == '-')
51 neg = 1;
52 p++;
53 nptr_len--;
54 }
55
56 if (!nptr_len)
57 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 if (base == 0) {
66 if (*p != '0')
67 base = 10;
68 else if (nptr_len > 2 && (p[1] == 'x' || p[1] == 'X'))
69 base = 16;
70 else
71 base = 8;
72 }
73
74 if (base < 0 || 36 < base)
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 if (base == 16 && nptr_len > 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
85 p += 2;
86 nptr_len -= 2;
87 }
88
89 /*
90 * Non-empty sequence of digits
91 */
92 for (; nptr_len > 0; p++,ndig++,nptr_len--) {
93 c = *p;
94 v = base;
95 if ('0'<=c && c<='9')
96 v = c - '0';
97 else if ('a'<=c && c<='z')
98 v = c - 'a' + 10;
99 else if ('A'<=c && c<='Z')
100 v = c - 'A' + 10;
101 if (v >= base)
102 break;
103 v = neg ? -v : v;
104 if (n > INT64_MAX / base || n < INT64_MIN / base) {
105 ovfl = 1;
106 /* Keep on iterating until the end of this number */
107 continue;
108 }
109 nn = n * base;
110 if ((v > 0 && nn > INT64_MAX - v) ||
111 (v < 0 && nn < INT64_MIN - v)) {
112 ovfl = 1;
113 /* Keep on iterating until the end of this number */
114 continue;
115 }
116 n = nn + v;
117 }
118
119 Return:
120 if (ndig == 0) {
121 git_error_set(GIT_ERROR_INVALID, "failed to convert string to long: not a number");
122 return -1;
123 }
124
125 if (endptr)
126 *endptr = p;
127
128 if (ovfl) {
129 git_error_set(GIT_ERROR_INVALID, "failed to convert string to long: overflow error");
130 return -1;
131 }
132
133 *result = n;
134 return 0;
135 }
136
137 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 if ((error = git__strntol64(&tmp_long, nptr, nptr_len, &tmp_endptr, base)) < 0)
145 return error;
146
147 tmp_int = tmp_long & 0xFFFFFFFF;
148 if (tmp_int != tmp_long) {
149 int len = (int)(tmp_endptr - nptr);
150 git_error_set(GIT_ERROR_INVALID, "failed to convert: '%.*s' is too large", len, nptr);
151 return -1;
152 }
153
154 *result = tmp_int;
155 if (endptr)
156 *endptr = tmp_endptr;
157
158 return error;
159 }
160
161 int git__strcasecmp(const char *a, const char *b)
162 {
163 while (*a && *b && git__tolower(*a) == git__tolower(*b))
164 ++a, ++b;
165 return ((unsigned char)git__tolower(*a) - (unsigned char)git__tolower(*b));
166 }
167
168 int git__strcasesort_cmp(const char *a, const char *b)
169 {
170 int cmp = 0;
171
172 while (*a && *b) {
173 if (*a != *b) {
174 if (git__tolower(*a) != git__tolower(*b))
175 break;
176 /* use case in sort order even if not in equivalence */
177 if (!cmp)
178 cmp = (int)(*(const uint8_t *)a) - (int)(*(const uint8_t *)b);
179 }
180
181 ++a, ++b;
182 }
183
184 if (*a || *b)
185 return (unsigned char)git__tolower(*a) - (unsigned char)git__tolower(*b);
186
187 return cmp;
188 }
189
190 int git__strncasecmp(const char *a, const char *b, size_t sz)
191 {
192 int al, bl;
193
194 do {
195 al = (unsigned char)git__tolower(*a);
196 bl = (unsigned char)git__tolower(*b);
197 ++a, ++b;
198 } while (--sz && al && al == bl);
199
200 return al - bl;
201 }
202
203 void git__strntolower(char *str, size_t len)
204 {
205 size_t i;
206
207 for (i = 0; i < len; ++i) {
208 str[i] = (char)git__tolower(str[i]);
209 }
210 }
211
212 void git__strtolower(char *str)
213 {
214 git__strntolower(str, strlen(str));
215 }
216
217 GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, bool icase)
218 {
219 int s, p;
220
221 while (str_n--) {
222 s = (unsigned char)*str++;
223 p = (unsigned char)*prefix++;
224
225 if (icase) {
226 s = git__tolower(s);
227 p = git__tolower(p);
228 }
229
230 if (!p)
231 return 0;
232
233 if (s != p)
234 return s - p;
235 }
236
237 return (0 - *prefix);
238 }
239
240 int git__prefixcmp(const char *str, const char *prefix)
241 {
242 unsigned char s, p;
243
244 while (1) {
245 p = *prefix++;
246 s = *str++;
247
248 if (!p)
249 return 0;
250
251 if (s != p)
252 return s - p;
253 }
254 }
255
256 int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
257 {
258 return prefixcmp(str, str_n, prefix, false);
259 }
260
261 int git__prefixcmp_icase(const char *str, const char *prefix)
262 {
263 return prefixcmp(str, SIZE_MAX, prefix, true);
264 }
265
266 int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
267 {
268 return prefixcmp(str, str_n, prefix, true);
269 }
270
271 int git__suffixcmp(const char *str, const char *suffix)
272 {
273 size_t a = strlen(str);
274 size_t b = strlen(suffix);
275 if (a < b)
276 return -1;
277 return strcmp(str + (a - b), suffix);
278 }
279
280 char *git__strtok(char **end, const char *sep)
281 {
282 char *ptr = *end;
283
284 while (*ptr && strchr(sep, *ptr))
285 ++ptr;
286
287 if (*ptr) {
288 char *start = ptr;
289 *end = start + 1;
290
291 while (**end && !strchr(sep, **end))
292 ++*end;
293
294 if (**end) {
295 **end = '\0';
296 ++*end;
297 }
298
299 return start;
300 }
301
302 return NULL;
303 }
304
305 /* Similar to strtok, but does not collapse repeated tokens. */
306 char *git__strsep(char **end, const char *sep)
307 {
308 char *start = *end, *ptr = *end;
309
310 while (*ptr && !strchr(sep, *ptr))
311 ++ptr;
312
313 if (*ptr) {
314 *end = ptr + 1;
315 *ptr = '\0';
316
317 return start;
318 }
319
320 return NULL;
321 }
322
323 size_t git__linenlen(const char *buffer, size_t buffer_len)
324 {
325 char *nl = memchr(buffer, '\n', buffer_len);
326 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 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 if (needlelen > haystacklen || !haystacklen || !needlelen)
339 return NULL;
340
341 h = (const char *) haystack,
342 n = (const char *) needle;
343
344 if (needlelen == 1)
345 return memchr(haystack, *n, haystacklen);
346
347 if (n[0] == n[1]) {
348 k = 2;
349 l = 1;
350 } else {
351 k = 1;
352 l = 2;
353 }
354
355 j = 0;
356 while (j <= haystacklen - needlelen) {
357 if (n[1] != h[j + 1]) {
358 j += k;
359 } else {
360 if (memcmp(n + 2, h + j + 2, needlelen - 2) == 0 &&
361 n[0] == h[j])
362 return h + j;
363 j += l;
364 }
365 }
366
367 return NULL;
368 }
369
370 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 line_count = (len / LINE_WIDTH);
378 last_line = (len % LINE_WIDTH);
379
380 for (i = 0; i < line_count; ++i) {
381 printf("%08" PRIxZ " ", (i * LINE_WIDTH));
382
383 line = buffer + (i * LINE_WIDTH);
384 for (j = 0; j < LINE_WIDTH; ++j, ++line) {
385 printf("%02x ", (unsigned char)*line & 0xFF);
386
387 if (j == (LINE_WIDTH / 2))
388 printf(" ");
389 }
390
391 printf(" |");
392
393 line = buffer + (i * LINE_WIDTH);
394 for (j = 0; j < LINE_WIDTH; ++j, ++line)
395 printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
396
397 printf("|\n");
398 }
399
400 if (last_line > 0) {
401 printf("%08" PRIxZ " ", (line_count * LINE_WIDTH));
402
403 line = buffer + (line_count * LINE_WIDTH);
404 for (j = 0; j < last_line; ++j, ++line) {
405 printf("%02x ", (unsigned char)*line & 0xFF);
406
407 if (j == (LINE_WIDTH / 2))
408 printf(" ");
409 }
410
411 if (j < (LINE_WIDTH / 2))
412 printf(" ");
413 for (j = 0; j < (LINE_WIDTH - last_line); ++j)
414 printf(" ");
415
416 printf(" |");
417
418 line = buffer + (line_count * LINE_WIDTH);
419 for (j = 0; j < last_line; ++j, ++line)
420 printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
421
422 printf("|\n");
423 }
424
425 printf("\n");
426 }
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 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 const uint8_t *data = (const uint8_t*)key;
486 const int nblocks = len / 4;
487
488 const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
489 const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
490
491 uint32_t h1 = 0x971e137b ^ seed;
492 uint32_t k1;
493
494 uint32_t c1 = 0x95543787;
495 uint32_t c2 = 0x2ad7eb25;
496
497 int i;
498
499 for (i = -nblocks; i; i++) {
500 k1 = blocks[i];
501 MURMUR_BLOCK();
502 }
503
504 k1 = 0;
505
506 switch(len & 3) {
507 case 3: k1 ^= tail[2] << 16;
508 /* fall through */
509 case 2: k1 ^= tail[1] << 8;
510 /* fall through */
511 case 1: k1 ^= tail[0];
512 MURMUR_BLOCK();
513 }
514
515 h1 ^= len;
516 h1 ^= h1 >> 16;
517 h1 *= 0x85ebca6b;
518 h1 ^= h1 >> 13;
519 h1 *= 0xc2b2ae35;
520 h1 ^= h1 >> 16;
521
522 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 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 int cmp = -1;
565 void **part, **base = array;
566
567 for (lim = array_len; lim != 0; lim >>= 1) {
568 part = base + (lim >> 1);
569 cmp = (*compare)(key, *part);
570 if (cmp == 0) {
571 base = part;
572 break;
573 }
574 if (cmp > 0) { /* key > p; take right partition */
575 base = part + 1;
576 lim--;
577 } /* else take left partition */
578 }
579
580 if (position)
581 *position = (base - array);
582
583 return (cmp == 0) ? 0 : GIT_ENOTFOUND;
584 }
585
586 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 int cmp = -1;
596 void **part, **base = array;
597
598 for (lim = array_len; lim != 0; lim >>= 1) {
599 part = base + (lim >> 1);
600 cmp = (*compare_r)(key, *part, payload);
601 if (cmp == 0) {
602 base = part;
603 break;
604 }
605 if (cmp > 0) { /* key > p; take right partition */
606 base = part + 1;
607 lim--;
608 } /* else take left partition */
609 }
610
611 if (position)
612 *position = (base - array);
613
614 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 int git__strcmp_cb(const void *a, const void *b)
624 {
625 return strcmp((const char *)a, (const char *)b);
626 }
627
628 int git__strcasecmp_cb(const void *a, const void *b)
629 {
630 return strcasecmp((const char *)a, (const char *)b);
631 }
632
633 int git__parse_bool(int *out, const char *value)
634 {
635 /* A missing value means true */
636 if (value == NULL ||
637 !strcasecmp(value, "true") ||
638 !strcasecmp(value, "yes") ||
639 !strcasecmp(value, "on")) {
640 *out = 1;
641 return 0;
642 }
643 if (!strcasecmp(value, "false") ||
644 !strcasecmp(value, "no") ||
645 !strcasecmp(value, "off") ||
646 value[0] == '\0') {
647 *out = 0;
648 return 0;
649 }
650
651 return -1;
652 }
653
654 size_t git__unescape(char *str)
655 {
656 char *scan, *pos = str;
657
658 if (!str)
659 return 0;
660
661 for (scan = str; *scan; pos++, scan++) {
662 if (*scan == '\\' && *(scan + 1) != '\0')
663 scan++; /* skip '\' but include next char */
664 if (pos != scan)
665 *pos = *scan;
666 }
667
668 if (pos != scan) {
669 *pos = '\0';
670 }
671
672 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 static void swap(uint8_t *a, uint8_t *b, size_t elsize)
694 {
695 char tmp[256];
696
697 while (elsize) {
698 size_t n = elsize < sizeof(tmp) ? elsize : sizeof(tmp);
699 memcpy(tmp, a + elsize - n, n);
700 memcpy(a + elsize - n, b + elsize - n, n);
701 memcpy(b + elsize - n, tmp, n);
702 elsize -= n;
703 }
704 }
705
706 static void insertsort(
707 void *els, size_t nel, size_t elsize,
708 git__sort_r_cmp cmp, void *payload)
709 {
710 uint8_t *base = els;
711 uint8_t *end = base + nel * elsize;
712 uint8_t *i, *j;
713
714 for (i = base + elsize; i < end; i += elsize)
715 for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize)
716 swap(j, j - elsize, elsize);
717 }
718 #endif
719
720 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 insertsort(els, nel, elsize, cmp, payload);
733 #endif
734 }
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 static int util_utf8_charlen(const uint8_t *str, size_t str_len)
781 {
782 size_t length, i;
783
784 length = utf8proc_utf8class[str[0]];
785 if (!length)
786 return -1;
787
788 if (str_len > 0 && length > str_len)
789 return -1;
790
791 for (i = 1; i < length; i++) {
792 if ((str[i] & 0xC0) != 0x80)
793 return -1;
794 }
795
796 return (int)length;
797 }
798
799 int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst)
800 {
801 int length;
802 int32_t uc = -1;
803
804 *dst = -1;
805 length = util_utf8_charlen(str, str_len);
806 if (length < 0)
807 return -1;
808
809 switch (length) {
810 case 1:
811 uc = str[0];
812 break;
813 case 2:
814 uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
815 if (uc < 0x80) uc = -1;
816 break;
817 case 3:
818 uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6)
819 + (str[2] & 0x3F);
820 if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
821 (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
822 break;
823 case 4:
824 uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
825 + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
826 if (uc < 0x10000 || uc >= 0x110000) uc = -1;
827 break;
828 }
829
830 if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE))
831 return -1;
832
833 *dst = uc;
834 return length;
835 }
836
837 size_t git__utf8_valid_buf_length(const uint8_t *str, size_t str_len)
838 {
839 size_t offset = 0;
840
841 while (offset < str_len) {
842 int length = util_utf8_charlen(str + offset, str_len - offset);
843
844 if (length < 0)
845 break;
846
847 offset += length;
848 }
849
850 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 int git__getenv(git_buf *out, const char *name)
885 {
886 const char *val = getenv(name);
887
888 git_buf_clear(out);
889
890 if (!val)
891 return GIT_ENOTFOUND;
892
893 return git_buf_puts(out, val);
894 }
895 #endif