]> git.proxmox.com Git - libgit2.git/blame - src/util.c
Test for ignore_case ranges on workdir iterator
[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 */
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
18void 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
25int 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
37void 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
46int 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 75int 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
139Return:
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 157int 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
177int 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
184int 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
191int 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
200int 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 213void 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
222void git__strtolower(char *str)
223{
224 git__strntolower(str, strlen(str));
225}
226
9eb79764
SP
227int 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
238int git__prefixcmp_icase(const char *str, const char *prefix)
239{
240 return strncasecmp(str, prefix, strlen(prefix));
241}
242
9eb79764
SP
243int 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 252char *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. */
278char *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
295void 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
341uint32_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*/
384uint32_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
466int 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 */
502int 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
510int 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
531size_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}