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