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