]> git.proxmox.com Git - libgit2.git/blame - src/util.c
Merge pull request #709 from arrbee/profiling-with-scottg
[libgit2.git] / src / util.c
CommitLineData
bb742ede 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
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
955f9ae9
VM
25void git_strarray_free(git_strarray *array)
26{
27 size_t i;
28 for (i = 0; i < array->count; ++i)
3286c408 29 git__free(array->strings[i]);
955f9ae9 30
3286c408 31 git__free(array->strings);
955f9ae9
VM
32}
33
14a513e0
RB
34int git_strarray_copy(git_strarray *tgt, const git_strarray *src)
35{
36 size_t i;
37
38 assert(tgt && src);
39
40 memset(tgt, 0, sizeof(*tgt));
41
42 if (!src->count)
43 return 0;
44
45 tgt->strings = git__calloc(src->count, sizeof(char *));
46 GITERR_CHECK_ALLOC(tgt->strings);
47
48 for (i = 0; i < src->count; ++i) {
49 tgt->strings[tgt->count] = git__strdup(src->strings[i]);
50
51 if (!tgt->strings[tgt->count]) {
52 git_strarray_free(tgt);
53 memset(tgt, 0, sizeof(*tgt));
54 return -1;
55 }
56
57 tgt->count++;
58 }
59
60 return 0;
61}
62
fafd4710 63int git__strtol64(int64_t *result, const char *nptr, const char **endptr, int base)
c6e65aca
VM
64{
65 const char *p;
fafd4710 66 int64_t n, nn;
c6e65aca
VM
67 int c, ovfl, v, neg, ndig;
68
69 p = nptr;
70 neg = 0;
71 n = 0;
72 ndig = 0;
73 ovfl = 0;
74
75 /*
76 * White space
77 */
0f49200c 78 while (git__isspace(*p))
c6e65aca
VM
79 p++;
80
81 /*
82 * Sign
83 */
84 if (*p == '-' || *p == '+')
85 if (*p++ == '-')
86 neg = 1;
87
88 /*
89 * Base
90 */
91 if (base == 0) {
92 if (*p != '0')
93 base = 10;
94 else {
95 base = 8;
96 if (p[1] == 'x' || p[1] == 'X') {
97 p += 2;
98 base = 16;
99 }
100 }
101 } else if (base == 16 && *p == '0') {
102 if (p[1] == 'x' || p[1] == 'X')
103 p += 2;
104 } else if (base < 0 || 36 < base)
105 goto Return;
106
107 /*
108 * Non-empty sequence of digits
109 */
110 for (;; p++,ndig++) {
111 c = *p;
112 v = base;
113 if ('0'<=c && c<='9')
114 v = c - '0';
115 else if ('a'<=c && c<='z')
116 v = c - 'a' + 10;
117 else if ('A'<=c && c<='Z')
118 v = c - 'A' + 10;
119 if (v >= base)
120 break;
121 nn = n*base + v;
122 if (nn < n)
123 ovfl = 1;
124 n = nn;
125 }
126
127Return:
7c7ff7d1
RB
128 if (ndig == 0) {
129 giterr_set(GITERR_INVALID, "Failed to convert string to long. Not a number");
130 return -1;
131 }
c6e65aca
VM
132
133 if (endptr)
134 *endptr = p;
135
7c7ff7d1
RB
136 if (ovfl) {
137 giterr_set(GITERR_INVALID, "Failed to convert string to long. Overflow error");
138 return -1;
139 }
c6e65aca
VM
140
141 *result = neg ? -n : n;
7c7ff7d1 142 return 0;
c6e65aca
VM
143}
144
fafd4710 145int git__strtol32(int32_t *result, const char *nptr, const char **endptr, int base)
ad196c6a 146{
7c7ff7d1 147 int error;
fafd4710
VM
148 int32_t tmp_int;
149 int64_t tmp_long;
ad196c6a 150
7c7ff7d1 151 if ((error = git__strtol64(&tmp_long, nptr, endptr, base)) < 0)
ad196c6a 152 return error;
153
154 tmp_int = tmp_long & 0xFFFFFFFF;
7c7ff7d1
RB
155 if (tmp_int != tmp_long) {
156 giterr_set(GITERR_INVALID, "Failed to convert. '%s' is too large", nptr);
157 return -1;
158 }
ad196c6a 159
160 *result = tmp_int;
7c7ff7d1 161
ad196c6a 162 return error;
163}
164
26e74c6a 165void git__strntolower(char *str, size_t len)
0da2c700 166{
26e74c6a 167 size_t i;
0da2c700
VM
168
169 for (i = 0; i < len; ++i) {
3a1c4310 170 str[i] = (char) tolower(str[i]);
0da2c700
VM
171 }
172}
173
174void git__strtolower(char *str)
175{
176 git__strntolower(str, strlen(str));
177}
178
9eb79764
SP
179int git__prefixcmp(const char *str, const char *prefix)
180{
181 for (;;) {
182 char p = *(prefix++), s;
183 if (!p)
184 return 0;
185 if ((s = *(str++)) != p)
186 return s - p;
187 }
188}
189
190int git__suffixcmp(const char *str, const char *suffix)
191{
192 size_t a = strlen(str);
193 size_t b = strlen(suffix);
194 if (a < b)
195 return -1;
196 return strcmp(str + (a - b), suffix);
197}
ced645ea 198
0291b5b7 199char *git__strtok(char **end, const char *sep)
f725931b 200{
0291b5b7 201 char *ptr = *end;
ced645ea 202
0291b5b7
VM
203 while (*ptr && strchr(sep, *ptr))
204 ++ptr;
f725931b 205
0291b5b7
VM
206 if (*ptr) {
207 char *start = ptr;
208 *end = start + 1;
ced645ea 209
0291b5b7
VM
210 while (**end && !strchr(sep, **end))
211 ++*end;
f725931b 212
0291b5b7
VM
213 if (**end) {
214 **end = '\0';
215 ++*end;
216 }
217
218 return start;
219 }
220
221 return NULL;
ced645ea
RJ
222}
223
0e465f97
VM
224void git__hexdump(const char *buffer, size_t len)
225{
226 static const size_t LINE_WIDTH = 16;
227
228 size_t line_count, last_line, i, j;
229 const char *line;
230
231 line_count = (len / LINE_WIDTH);
232 last_line = (len % LINE_WIDTH);
233
234 for (i = 0; i < line_count; ++i) {
235 line = buffer + (i * LINE_WIDTH);
236 for (j = 0; j < LINE_WIDTH; ++j, ++line)
237 printf("%02X ", (unsigned char)*line & 0xFF);
238
239 printf("| ");
240
241 line = buffer + (i * LINE_WIDTH);
242 for (j = 0; j < LINE_WIDTH; ++j, ++line)
243 printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
244
245 printf("\n");
246 }
247
248 if (last_line > 0) {
249
250 line = buffer + (line_count * LINE_WIDTH);
251 for (j = 0; j < last_line; ++j, ++line)
252 printf("%02X ", (unsigned char)*line & 0xFF);
253
254 for (j = 0; j < (LINE_WIDTH - last_line); ++j)
87d9869f 255 printf(" ");
0e465f97
VM
256
257 printf("| ");
258
259 line = buffer + (line_count * LINE_WIDTH);
260 for (j = 0; j < last_line; ++j, ++line)
261 printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
262
263 printf("\n");
264 }
265
266 printf("\n");
267}
e0646b38
VM
268
269#ifdef GIT_LEGACY_HASH
270uint32_t git__hash(const void *key, int len, unsigned int seed)
271{
272 const uint32_t m = 0x5bd1e995;
273 const int r = 24;
274 uint32_t h = seed ^ len;
275
276 const unsigned char *data = (const unsigned char *)key;
277
278 while(len >= 4) {
279 uint32_t k = *(uint32_t *)data;
280
932d1baf
KS
281 k *= m;
282 k ^= k >> r;
283 k *= m;
284
285 h *= m;
e0646b38
VM
286 h ^= k;
287
288 data += 4;
289 len -= 4;
290 }
932d1baf 291
e0646b38
VM
292 switch(len) {
293 case 3: h ^= data[2] << 16;
294 case 2: h ^= data[1] << 8;
295 case 1: h ^= data[0];
87d9869f 296 h *= m;
e0646b38
VM
297 };
298
299 h ^= h >> 13;
300 h *= m;
301 h ^= h >> 15;
302
303 return h;
932d1baf 304}
e0646b38
VM
305#else
306/*
307 Cross-platform version of Murmurhash3
308 http://code.google.com/p/smhasher/wiki/MurmurHash3
309 by Austin Appleby (aappleby@gmail.com)
310
311 This code is on the public domain.
312*/
313uint32_t git__hash(const void *key, int len, uint32_t seed)
314{
315
316#define MURMUR_BLOCK() {\
87d9869f
VM
317 k1 *= c1; \
318 k1 = git__rotl(k1,11);\
319 k1 *= c2;\
320 h1 ^= k1;\
321 h1 = h1*3 + 0x52dce729;\
322 c1 = c1*5 + 0x7b7d159c;\
323 c2 = c2*5 + 0x6bce6396;\
e0646b38
VM
324}
325
326 const uint8_t *data = (const uint8_t*)key;
327 const int nblocks = len / 4;
328
329 const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
330 const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
331
332 uint32_t h1 = 0x971e137b ^ seed;
333 uint32_t k1;
334
335 uint32_t c1 = 0x95543787;
336 uint32_t c2 = 0x2ad7eb25;
337
338 int i;
339
340 for (i = -nblocks; i; i++) {
341 k1 = blocks[i];
342 MURMUR_BLOCK();
343 }
344
345 k1 = 0;
346
347 switch(len & 3) {
348 case 3: k1 ^= tail[2] << 16;
349 case 2: k1 ^= tail[1] << 8;
350 case 1: k1 ^= tail[0];
351 MURMUR_BLOCK();
352 }
353
354 h1 ^= len;
355 h1 ^= h1 >> 16;
356 h1 *= 0x85ebca6b;
357 h1 ^= h1 >> 13;
358 h1 *= 0xc2b2ae35;
359 h1 ^= h1 >> 16;
360
361 return h1;
932d1baf 362}
e0646b38 363#endif
c20ffa61 364
de18f276
VM
365/**
366 * A modified `bsearch` from the BSD glibc.
367 *
368 * Copyright (c) 1990 Regents of the University of California.
369 * All rights reserved.
c20ffa61 370 */
bd370b14
RB
371int git__bsearch(
372 void **array,
373 size_t array_len,
374 const void *key,
375 int (*compare)(const void *, const void *),
376 size_t *position)
c20ffa61 377{
44ef8b1b
RB
378 unsigned int lim;
379 int cmp = -1;
bd370b14
RB
380 void **part, **base = array;
381
44ef8b1b 382 for (lim = (unsigned int)array_len; lim != 0; lim >>= 1) {
bd370b14
RB
383 part = base + (lim >> 1);
384 cmp = (*compare)(key, *part);
385 if (cmp == 0) {
ae9e29fd
RB
386 base = part;
387 break;
388 }
389 if (cmp > 0) { /* key > p; take right partition */
bd370b14
RB
390 base = part + 1;
391 lim--;
392 } /* else take left partition */
393 }
394
ae9e29fd
RB
395 if (position)
396 *position = (base - array);
397
398 return (cmp == 0) ? 0 : -1;
c20ffa61
KS
399}
400
d1f34693 401/**
402 * A strcmp wrapper
403 *
404 * We don't want direct pointers to the CRT on Windows, we may
405 * get stdcall conflicts.
406 */
407int git__strcmp_cb(const void *a, const void *b)
408{
409 const char *stra = (const char *)a;
410 const char *strb = (const char *)b;
411
412 return strcmp(stra, strb);
84dd3820 413}