]>
Commit | Line | Data |
---|---|---|
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 | */ | |
536955f9 | 7 | #include <git2.h> |
64a47c01 | 8 | #include "common.h" |
2c4b7707 SP |
9 | #include <stdarg.h> |
10 | #include <stdio.h> | |
c6e65aca | 11 | #include <ctype.h> |
e9c6571d | 12 | #include "posix.h" |
64a47c01 | 13 | |
ae2e4c6a | 14 | #ifdef _MSC_VER |
63f91e1c | 15 | # include <Shlwapi.h> |
63f91e1c CMN |
16 | #endif |
17 | ||
536955f9 VM |
18 | void git_libgit2_version(int *major, int *minor, int *rev) |
19 | { | |
20 | *major = LIBGIT2_VER_MAJOR; | |
21 | *minor = LIBGIT2_VER_MINOR; | |
22 | *rev = LIBGIT2_VER_REVISION; | |
23 | } | |
24 | ||
e564e496 SC |
25 | int git_libgit2_capabilities() |
26 | { | |
27 | return 0 | |
28 | #ifdef GIT_THREADS | |
29 | | GIT_CAP_THREADS | |
30 | #endif | |
3ce22c74 | 31 | #if defined(GIT_SSL) || defined(GIT_WINHTTP) |
e564e496 SC |
32 | | GIT_CAP_HTTPS |
33 | #endif | |
34 | ; | |
35 | } | |
36 | ||
955f9ae9 VM |
37 | void git_strarray_free(git_strarray *array) |
38 | { | |
39 | size_t i; | |
40 | for (i = 0; i < array->count; ++i) | |
3286c408 | 41 | git__free(array->strings[i]); |
955f9ae9 | 42 | |
3286c408 | 43 | git__free(array->strings); |
955f9ae9 VM |
44 | } |
45 | ||
14a513e0 RB |
46 | int git_strarray_copy(git_strarray *tgt, const git_strarray *src) |
47 | { | |
48 | size_t i; | |
49 | ||
50 | assert(tgt && src); | |
51 | ||
52 | memset(tgt, 0, sizeof(*tgt)); | |
53 | ||
54 | if (!src->count) | |
55 | return 0; | |
56 | ||
57 | tgt->strings = git__calloc(src->count, sizeof(char *)); | |
58 | GITERR_CHECK_ALLOC(tgt->strings); | |
59 | ||
60 | for (i = 0; i < src->count; ++i) { | |
61 | tgt->strings[tgt->count] = git__strdup(src->strings[i]); | |
62 | ||
63 | if (!tgt->strings[tgt->count]) { | |
64 | git_strarray_free(tgt); | |
65 | memset(tgt, 0, sizeof(*tgt)); | |
66 | return -1; | |
67 | } | |
68 | ||
69 | tgt->count++; | |
70 | } | |
71 | ||
72 | return 0; | |
73 | } | |
74 | ||
fafd4710 | 75 | int git__strtol64(int64_t *result, const char *nptr, const char **endptr, int base) |
c6e65aca VM |
76 | { |
77 | const char *p; | |
fafd4710 | 78 | int64_t n, nn; |
c6e65aca VM |
79 | int c, ovfl, v, neg, ndig; |
80 | ||
81 | p = nptr; | |
82 | neg = 0; | |
83 | n = 0; | |
84 | ndig = 0; | |
85 | ovfl = 0; | |
86 | ||
87 | /* | |
88 | * White space | |
89 | */ | |
0f49200c | 90 | while (git__isspace(*p)) |
c6e65aca VM |
91 | p++; |
92 | ||
93 | /* | |
94 | * Sign | |
95 | */ | |
96 | if (*p == '-' || *p == '+') | |
97 | if (*p++ == '-') | |
98 | neg = 1; | |
99 | ||
100 | /* | |
101 | * Base | |
102 | */ | |
103 | if (base == 0) { | |
104 | if (*p != '0') | |
105 | base = 10; | |
106 | else { | |
107 | base = 8; | |
108 | if (p[1] == 'x' || p[1] == 'X') { | |
109 | p += 2; | |
110 | base = 16; | |
111 | } | |
112 | } | |
113 | } else if (base == 16 && *p == '0') { | |
114 | if (p[1] == 'x' || p[1] == 'X') | |
115 | p += 2; | |
116 | } else if (base < 0 || 36 < base) | |
117 | goto Return; | |
118 | ||
119 | /* | |
120 | * Non-empty sequence of digits | |
121 | */ | |
122 | for (;; p++,ndig++) { | |
123 | c = *p; | |
124 | v = base; | |
125 | if ('0'<=c && c<='9') | |
126 | v = c - '0'; | |
127 | else if ('a'<=c && c<='z') | |
128 | v = c - 'a' + 10; | |
129 | else if ('A'<=c && c<='Z') | |
130 | v = c - 'A' + 10; | |
131 | if (v >= base) | |
132 | break; | |
133 | nn = n*base + v; | |
134 | if (nn < n) | |
135 | ovfl = 1; | |
136 | n = nn; | |
137 | } | |
138 | ||
139 | Return: | |
7c7ff7d1 RB |
140 | if (ndig == 0) { |
141 | giterr_set(GITERR_INVALID, "Failed to convert string to long. Not a number"); | |
142 | return -1; | |
143 | } | |
c6e65aca VM |
144 | |
145 | if (endptr) | |
146 | *endptr = p; | |
147 | ||
7c7ff7d1 RB |
148 | if (ovfl) { |
149 | giterr_set(GITERR_INVALID, "Failed to convert string to long. Overflow error"); | |
150 | return -1; | |
151 | } | |
c6e65aca VM |
152 | |
153 | *result = neg ? -n : n; | |
7c7ff7d1 | 154 | return 0; |
c6e65aca VM |
155 | } |
156 | ||
fafd4710 | 157 | int git__strtol32(int32_t *result, const char *nptr, const char **endptr, int base) |
ad196c6a | 158 | { |
7c7ff7d1 | 159 | int error; |
fafd4710 VM |
160 | int32_t tmp_int; |
161 | int64_t tmp_long; | |
ad196c6a | 162 | |
7c7ff7d1 | 163 | if ((error = git__strtol64(&tmp_long, nptr, endptr, base)) < 0) |
ad196c6a | 164 | return error; |
165 | ||
166 | tmp_int = tmp_long & 0xFFFFFFFF; | |
7c7ff7d1 RB |
167 | if (tmp_int != tmp_long) { |
168 | giterr_set(GITERR_INVALID, "Failed to convert. '%s' is too large", nptr); | |
169 | return -1; | |
170 | } | |
ad196c6a | 171 | |
172 | *result = tmp_int; | |
7c7ff7d1 | 173 | |
ad196c6a | 174 | return error; |
175 | } | |
176 | ||
a277345e RB |
177 | int git__strcmp(const char *a, const char *b) |
178 | { | |
179 | while (*a && *b && *a == *b) | |
180 | ++a, ++b; | |
181 | return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b); | |
182 | } | |
183 | ||
184 | int git__strcasecmp(const char *a, const char *b) | |
185 | { | |
186 | while (*a && *b && tolower(*a) == tolower(*b)) | |
187 | ++a, ++b; | |
188 | return (tolower(*a) - tolower(*b)); | |
189 | } | |
190 | ||
191 | int git__strncmp(const char *a, const char *b, size_t sz) | |
192 | { | |
193 | while (sz && *a && *b && *a == *b) | |
194 | --sz, ++a, ++b; | |
195 | if (!sz) | |
196 | return 0; | |
197 | return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b); | |
198 | } | |
199 | ||
200 | int git__strncasecmp(const char *a, const char *b, size_t sz) | |
201 | { | |
0db4cd04 | 202 | int al, bl; |
91e7d263 | 203 | |
0db4cd04 | 204 | do { |
91e7d263 RB |
205 | al = (unsigned char)tolower(*a); |
206 | bl = (unsigned char)tolower(*b); | |
0db4cd04 PK |
207 | ++a, ++b; |
208 | } while (--sz && al && al == bl); | |
91e7d263 | 209 | |
0db4cd04 | 210 | return al - bl; |
a277345e RB |
211 | } |
212 | ||
26e74c6a | 213 | void git__strntolower(char *str, size_t len) |
0da2c700 | 214 | { |
26e74c6a | 215 | size_t i; |
0da2c700 VM |
216 | |
217 | for (i = 0; i < len; ++i) { | |
3a1c4310 | 218 | str[i] = (char) tolower(str[i]); |
0da2c700 VM |
219 | } |
220 | } | |
221 | ||
222 | void git__strtolower(char *str) | |
223 | { | |
224 | git__strntolower(str, strlen(str)); | |
225 | } | |
226 | ||
9eb79764 SP |
227 | int git__prefixcmp(const char *str, const char *prefix) |
228 | { | |
229 | for (;;) { | |
8e60c712 | 230 | unsigned char p = *(prefix++), s; |
9eb79764 SP |
231 | if (!p) |
232 | return 0; | |
233 | if ((s = *(str++)) != p) | |
234 | return s - p; | |
235 | } | |
236 | } | |
237 | ||
ec40b7f9 PK |
238 | int git__prefixcmp_icase(const char *str, const char *prefix) |
239 | { | |
240 | return strncasecmp(str, prefix, strlen(prefix)); | |
241 | } | |
242 | ||
9eb79764 SP |
243 | int git__suffixcmp(const char *str, const char *suffix) |
244 | { | |
245 | size_t a = strlen(str); | |
246 | size_t b = strlen(suffix); | |
247 | if (a < b) | |
248 | return -1; | |
249 | return strcmp(str + (a - b), suffix); | |
250 | } | |
ced645ea | 251 | |
0291b5b7 | 252 | char *git__strtok(char **end, const char *sep) |
f725931b | 253 | { |
0291b5b7 | 254 | char *ptr = *end; |
ced645ea | 255 | |
0291b5b7 VM |
256 | while (*ptr && strchr(sep, *ptr)) |
257 | ++ptr; | |
f725931b | 258 | |
0291b5b7 VM |
259 | if (*ptr) { |
260 | char *start = ptr; | |
261 | *end = start + 1; | |
ced645ea | 262 | |
0291b5b7 VM |
263 | while (**end && !strchr(sep, **end)) |
264 | ++*end; | |
f725931b | 265 | |
0291b5b7 VM |
266 | if (**end) { |
267 | **end = '\0'; | |
268 | ++*end; | |
269 | } | |
270 | ||
271 | return start; | |
272 | } | |
273 | ||
274 | return NULL; | |
ced645ea RJ |
275 | } |
276 | ||
7fcec834 ET |
277 | /* Similar to strtok, but does not collapse repeated tokens. */ |
278 | char *git__strsep(char **end, const char *sep) | |
279 | { | |
280 | char *start = *end, *ptr = *end; | |
281 | ||
282 | while (*ptr && !strchr(sep, *ptr)) | |
283 | ++ptr; | |
284 | ||
285 | if (*ptr) { | |
286 | *end = ptr + 1; | |
287 | *ptr = '\0'; | |
288 | ||
289 | return start; | |
290 | } | |
291 | ||
292 | return NULL; | |
293 | } | |
294 | ||
0e465f97 VM |
295 | void git__hexdump(const char *buffer, size_t len) |
296 | { | |
297 | static const size_t LINE_WIDTH = 16; | |
298 | ||
299 | size_t line_count, last_line, i, j; | |
300 | const char *line; | |
301 | ||
302 | line_count = (len / LINE_WIDTH); | |
303 | last_line = (len % LINE_WIDTH); | |
304 | ||
305 | for (i = 0; i < line_count; ++i) { | |
306 | line = buffer + (i * LINE_WIDTH); | |
307 | for (j = 0; j < LINE_WIDTH; ++j, ++line) | |
308 | printf("%02X ", (unsigned char)*line & 0xFF); | |
309 | ||
310 | printf("| "); | |
311 | ||
312 | line = buffer + (i * LINE_WIDTH); | |
313 | for (j = 0; j < LINE_WIDTH; ++j, ++line) | |
314 | printf("%c", (*line >= 32 && *line <= 126) ? *line : '.'); | |
315 | ||
316 | printf("\n"); | |
317 | } | |
318 | ||
319 | if (last_line > 0) { | |
320 | ||
321 | line = buffer + (line_count * LINE_WIDTH); | |
322 | for (j = 0; j < last_line; ++j, ++line) | |
323 | printf("%02X ", (unsigned char)*line & 0xFF); | |
324 | ||
325 | for (j = 0; j < (LINE_WIDTH - last_line); ++j) | |
87d9869f | 326 | printf(" "); |
0e465f97 VM |
327 | |
328 | printf("| "); | |
329 | ||
330 | line = buffer + (line_count * LINE_WIDTH); | |
331 | for (j = 0; j < last_line; ++j, ++line) | |
332 | printf("%c", (*line >= 32 && *line <= 126) ? *line : '.'); | |
333 | ||
334 | printf("\n"); | |
335 | } | |
336 | ||
337 | printf("\n"); | |
338 | } | |
e0646b38 VM |
339 | |
340 | #ifdef GIT_LEGACY_HASH | |
341 | uint32_t git__hash(const void *key, int len, unsigned int seed) | |
342 | { | |
343 | const uint32_t m = 0x5bd1e995; | |
344 | const int r = 24; | |
345 | uint32_t h = seed ^ len; | |
346 | ||
347 | const unsigned char *data = (const unsigned char *)key; | |
348 | ||
349 | while(len >= 4) { | |
350 | uint32_t k = *(uint32_t *)data; | |
351 | ||
932d1baf KS |
352 | k *= m; |
353 | k ^= k >> r; | |
354 | k *= m; | |
355 | ||
356 | h *= m; | |
e0646b38 VM |
357 | h ^= k; |
358 | ||
359 | data += 4; | |
360 | len -= 4; | |
361 | } | |
932d1baf | 362 | |
e0646b38 VM |
363 | switch(len) { |
364 | case 3: h ^= data[2] << 16; | |
365 | case 2: h ^= data[1] << 8; | |
366 | case 1: h ^= data[0]; | |
87d9869f | 367 | h *= m; |
e0646b38 VM |
368 | }; |
369 | ||
370 | h ^= h >> 13; | |
371 | h *= m; | |
372 | h ^= h >> 15; | |
373 | ||
374 | return h; | |
932d1baf | 375 | } |
e0646b38 VM |
376 | #else |
377 | /* | |
378 | Cross-platform version of Murmurhash3 | |
379 | http://code.google.com/p/smhasher/wiki/MurmurHash3 | |
380 | by Austin Appleby (aappleby@gmail.com) | |
381 | ||
382 | This code is on the public domain. | |
383 | */ | |
384 | uint32_t git__hash(const void *key, int len, uint32_t seed) | |
385 | { | |
386 | ||
387 | #define MURMUR_BLOCK() {\ | |
87d9869f VM |
388 | k1 *= c1; \ |
389 | k1 = git__rotl(k1,11);\ | |
390 | k1 *= c2;\ | |
391 | h1 ^= k1;\ | |
392 | h1 = h1*3 + 0x52dce729;\ | |
393 | c1 = c1*5 + 0x7b7d159c;\ | |
394 | c2 = c2*5 + 0x6bce6396;\ | |
e0646b38 VM |
395 | } |
396 | ||
397 | const uint8_t *data = (const uint8_t*)key; | |
398 | const int nblocks = len / 4; | |
399 | ||
400 | const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); | |
401 | const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); | |
402 | ||
403 | uint32_t h1 = 0x971e137b ^ seed; | |
404 | uint32_t k1; | |
405 | ||
406 | uint32_t c1 = 0x95543787; | |
407 | uint32_t c2 = 0x2ad7eb25; | |
408 | ||
409 | int i; | |
410 | ||
411 | for (i = -nblocks; i; i++) { | |
412 | k1 = blocks[i]; | |
413 | MURMUR_BLOCK(); | |
414 | } | |
415 | ||
416 | k1 = 0; | |
417 | ||
418 | switch(len & 3) { | |
419 | case 3: k1 ^= tail[2] << 16; | |
420 | case 2: k1 ^= tail[1] << 8; | |
421 | case 1: k1 ^= tail[0]; | |
422 | MURMUR_BLOCK(); | |
423 | } | |
424 | ||
425 | h1 ^= len; | |
426 | h1 ^= h1 >> 16; | |
427 | h1 *= 0x85ebca6b; | |
428 | h1 ^= h1 >> 13; | |
429 | h1 *= 0xc2b2ae35; | |
430 | h1 ^= h1 >> 16; | |
431 | ||
432 | return h1; | |
932d1baf | 433 | } |
e0646b38 | 434 | #endif |
c20ffa61 | 435 | |
de18f276 VM |
436 | /** |
437 | * A modified `bsearch` from the BSD glibc. | |
438 | * | |
439 | * Copyright (c) 1990 Regents of the University of California. | |
440 | * All rights reserved. | |
0470f8fc MW |
441 | * Redistribution and use in source and binary forms, with or without |
442 | * modification, are permitted provided that the following conditions | |
443 | * are met: | |
444 | * 1. Redistributions of source code must retain the above copyright | |
445 | * notice, this list of conditions and the following disclaimer. | |
446 | * 2. Redistributions in binary form must reproduce the above copyright | |
447 | * notice, this list of conditions and the following disclaimer in the | |
448 | * documentation and/or other materials provided with the distribution. | |
449 | * 3. [rescinded 22 July 1999] | |
450 | * 4. Neither the name of the University nor the names of its contributors | |
451 | * may be used to endorse or promote products derived from this software | |
452 | * without specific prior written permission. | |
453 | * | |
454 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
455 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
456 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
457 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
458 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
459 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
460 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
461 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
462 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
463 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
464 | * SUCH DAMAGE. | |
465 | */ | |
bd370b14 RB |
466 | int git__bsearch( |
467 | void **array, | |
468 | size_t array_len, | |
469 | const void *key, | |
470 | int (*compare)(const void *, const void *), | |
471 | size_t *position) | |
c20ffa61 | 472 | { |
44ef8b1b RB |
473 | unsigned int lim; |
474 | int cmp = -1; | |
bd370b14 RB |
475 | void **part, **base = array; |
476 | ||
44ef8b1b | 477 | for (lim = (unsigned int)array_len; lim != 0; lim >>= 1) { |
bd370b14 RB |
478 | part = base + (lim >> 1); |
479 | cmp = (*compare)(key, *part); | |
480 | if (cmp == 0) { | |
ae9e29fd RB |
481 | base = part; |
482 | break; | |
483 | } | |
484 | if (cmp > 0) { /* key > p; take right partition */ | |
bd370b14 RB |
485 | base = part + 1; |
486 | lim--; | |
487 | } /* else take left partition */ | |
488 | } | |
489 | ||
ae9e29fd RB |
490 | if (position) |
491 | *position = (base - array); | |
492 | ||
493 | return (cmp == 0) ? 0 : -1; | |
c20ffa61 KS |
494 | } |
495 | ||
d1f34693 | 496 | /** |
497 | * A strcmp wrapper | |
16248ee2 | 498 | * |
d1f34693 | 499 | * We don't want direct pointers to the CRT on Windows, we may |
500 | * get stdcall conflicts. | |
501 | */ | |
502 | int git__strcmp_cb(const void *a, const void *b) | |
503 | { | |
504 | const char *stra = (const char *)a; | |
505 | const char *strb = (const char *)b; | |
506 | ||
507 | return strcmp(stra, strb); | |
84dd3820 | 508 | } |
29e948de VM |
509 | |
510 | int git__parse_bool(int *out, const char *value) | |
511 | { | |
512 | /* A missing value means true */ | |
47db054d CMN |
513 | if (value == NULL || |
514 | !strcasecmp(value, "true") || | |
29e948de VM |
515 | !strcasecmp(value, "yes") || |
516 | !strcasecmp(value, "on")) { | |
517 | *out = 1; | |
518 | return 0; | |
519 | } | |
520 | if (!strcasecmp(value, "false") || | |
521 | !strcasecmp(value, "no") || | |
47db054d CMN |
522 | !strcasecmp(value, "off") || |
523 | value[0] == '\0') { | |
29e948de VM |
524 | *out = 0; |
525 | return 0; | |
526 | } | |
527 | ||
528 | return -1; | |
529 | } | |
02a0d651 | 530 | |
531 | size_t git__unescape(char *str) | |
532 | { | |
533 | char *scan, *pos = str; | |
534 | ||
535 | for (scan = str; *scan; pos++, scan++) { | |
536 | if (*scan == '\\' && *(scan + 1) != '\0') | |
537 | scan++; /* skip '\' but include next char */ | |
538 | if (pos != scan) | |
539 | *pos = *scan; | |
540 | } | |
541 | ||
542 | if (pos != scan) { | |
543 | *pos = '\0'; | |
544 | } | |
545 | ||
546 | return (pos - str); | |
547 | } |