]> git.proxmox.com Git - libgit2.git/blob - src/util.c
Merge pull request #1204 from arrbee/diff-blob-to-buffer
[libgit2.git] / src / util.c
1 /*
2 * Copyright (C) 2009-2012 the libgit2 contributors
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 #include <git2.h>
8 #include "common.h"
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include "posix.h"
13
14 #ifdef _MSC_VER
15 # include <Shlwapi.h>
16 #endif
17
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
25 int git_libgit2_capabilities()
26 {
27 return 0
28 #ifdef GIT_THREADS
29 | GIT_CAP_THREADS
30 #endif
31 #if defined(GIT_SSL) || defined(GIT_WINHTTP)
32 | GIT_CAP_HTTPS
33 #endif
34 ;
35 }
36
37 void git_strarray_free(git_strarray *array)
38 {
39 size_t i;
40 for (i = 0; i < array->count; ++i)
41 git__free(array->strings[i]);
42
43 git__free(array->strings);
44 }
45
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
75 int git__strtol64(int64_t *result, const char *nptr, const char **endptr, int base)
76 {
77 const char *p;
78 int64_t n, nn;
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 */
90 while (git__isspace(*p))
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:
140 if (ndig == 0) {
141 giterr_set(GITERR_INVALID, "Failed to convert string to long. Not a number");
142 return -1;
143 }
144
145 if (endptr)
146 *endptr = p;
147
148 if (ovfl) {
149 giterr_set(GITERR_INVALID, "Failed to convert string to long. Overflow error");
150 return -1;
151 }
152
153 *result = neg ? -n : n;
154 return 0;
155 }
156
157 int git__strtol32(int32_t *result, const char *nptr, const char **endptr, int base)
158 {
159 int error;
160 int32_t tmp_int;
161 int64_t tmp_long;
162
163 if ((error = git__strtol64(&tmp_long, nptr, endptr, base)) < 0)
164 return error;
165
166 tmp_int = tmp_long & 0xFFFFFFFF;
167 if (tmp_int != tmp_long) {
168 giterr_set(GITERR_INVALID, "Failed to convert. '%s' is too large", nptr);
169 return -1;
170 }
171
172 *result = tmp_int;
173
174 return error;
175 }
176
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 {
202 int al, bl;
203
204 do {
205 al = (unsigned char)tolower(*a);
206 bl = (unsigned char)tolower(*b);
207 ++a, ++b;
208 } while (--sz && al && al == bl);
209
210 return al - bl;
211 }
212
213 void git__strntolower(char *str, size_t len)
214 {
215 size_t i;
216
217 for (i = 0; i < len; ++i) {
218 str[i] = (char) tolower(str[i]);
219 }
220 }
221
222 void git__strtolower(char *str)
223 {
224 git__strntolower(str, strlen(str));
225 }
226
227 int git__prefixcmp(const char *str, const char *prefix)
228 {
229 for (;;) {
230 unsigned char p = *(prefix++), s;
231 if (!p)
232 return 0;
233 if ((s = *(str++)) != p)
234 return s - p;
235 }
236 }
237
238 int git__prefixcmp_icase(const char *str, const char *prefix)
239 {
240 return strncasecmp(str, prefix, strlen(prefix));
241 }
242
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 }
251
252 char *git__strtok(char **end, const char *sep)
253 {
254 char *ptr = *end;
255
256 while (*ptr && strchr(sep, *ptr))
257 ++ptr;
258
259 if (*ptr) {
260 char *start = ptr;
261 *end = start + 1;
262
263 while (**end && !strchr(sep, **end))
264 ++*end;
265
266 if (**end) {
267 **end = '\0';
268 ++*end;
269 }
270
271 return start;
272 }
273
274 return NULL;
275 }
276
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
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)
326 printf(" ");
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 }
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
352 k *= m;
353 k ^= k >> r;
354 k *= m;
355
356 h *= m;
357 h ^= k;
358
359 data += 4;
360 len -= 4;
361 }
362
363 switch(len) {
364 case 3: h ^= data[2] << 16;
365 case 2: h ^= data[1] << 8;
366 case 1: h ^= data[0];
367 h *= m;
368 };
369
370 h ^= h >> 13;
371 h *= m;
372 h ^= h >> 15;
373
374 return h;
375 }
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() {\
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;\
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;
433 }
434 #endif
435
436 /**
437 * A modified `bsearch` from the BSD glibc.
438 *
439 * Copyright (c) 1990 Regents of the University of California.
440 * All rights reserved.
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 */
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)
472 {
473 unsigned int lim;
474 int cmp = -1;
475 void **part, **base = array;
476
477 for (lim = (unsigned int)array_len; lim != 0; lim >>= 1) {
478 part = base + (lim >> 1);
479 cmp = (*compare)(key, *part);
480 if (cmp == 0) {
481 base = part;
482 break;
483 }
484 if (cmp > 0) { /* key > p; take right partition */
485 base = part + 1;
486 lim--;
487 } /* else take left partition */
488 }
489
490 if (position)
491 *position = (base - array);
492
493 return (cmp == 0) ? 0 : -1;
494 }
495
496 /**
497 * A strcmp wrapper
498 *
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);
508 }
509
510 int git__parse_bool(int *out, const char *value)
511 {
512 /* A missing value means true */
513 if (value == NULL ||
514 !strcasecmp(value, "true") ||
515 !strcasecmp(value, "yes") ||
516 !strcasecmp(value, "on")) {
517 *out = 1;
518 return 0;
519 }
520 if (!strcasecmp(value, "false") ||
521 !strcasecmp(value, "no") ||
522 !strcasecmp(value, "off") ||
523 value[0] == '\0') {
524 *out = 0;
525 return 0;
526 }
527
528 return -1;
529 }
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 }