]>
git.proxmox.com Git - libgit2.git/blob - src/util.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
13 # include "win32/utf-conv.h"
14 # include "win32/w32_buffer.h"
25 int git__strntol64(int64_t *result
, const char *nptr
, size_t nptr_len
, const char **endptr
, int base
)
29 int c
, ovfl
, v
, neg
, ndig
;
40 while (nptr_len
&& git__isspace(*p
))
49 if (*p
== '-' || *p
== '+') {
60 * Automatically detect the base if none was given to us.
61 * Right now, we assume that a number starting with '0x'
62 * is hexadecimal and a number starting with '0' is
68 else if (nptr_len
> 2 && (p
[1] == 'x' || p
[1] == 'X'))
74 if (base
< 0 || 36 < base
)
78 * Skip prefix of '0x'-prefixed hexadecimal numbers. There is no
79 * need to do the same for '0'-prefixed octal numbers as a
80 * leading '0' does not have any impact. Also, if we skip a
81 * leading '0' in such a string, then we may end up with no
82 * digits left and produce an error later on which isn't one.
84 if (base
== 16 && nptr_len
> 2 && p
[0] == '0' && (p
[1] == 'x' || p
[1] == 'X')) {
90 * Non-empty sequence of digits
92 for (; nptr_len
> 0; p
++,ndig
++,nptr_len
--) {
97 else if ('a'<=c
&& c
<='z')
99 else if ('A'<=c
&& c
<='Z')
104 if (n
> INT64_MAX
/ base
|| n
< INT64_MIN
/ base
) {
106 /* Keep on iterating until the end of this number */
110 if ((v
> 0 && nn
> INT64_MAX
- v
) ||
111 (v
< 0 && nn
< INT64_MIN
- v
)) {
113 /* Keep on iterating until the end of this number */
121 git_error_set(GIT_ERROR_INVALID
, "failed to convert string to long: not a number");
129 git_error_set(GIT_ERROR_INVALID
, "failed to convert string to long: overflow error");
137 int git__strntol32(int32_t *result
, const char *nptr
, size_t nptr_len
, const char **endptr
, int base
)
139 const char *tmp_endptr
;
144 if ((error
= git__strntol64(&tmp_long
, nptr
, nptr_len
, &tmp_endptr
, base
)) < 0)
147 tmp_int
= tmp_long
& 0xFFFFFFFF;
148 if (tmp_int
!= tmp_long
) {
149 int len
= (int)(tmp_endptr
- nptr
);
150 git_error_set(GIT_ERROR_INVALID
, "failed to convert: '%.*s' is too large", len
, nptr
);
156 *endptr
= tmp_endptr
;
161 int git__strcasecmp(const char *a
, const char *b
)
163 while (*a
&& *b
&& git__tolower(*a
) == git__tolower(*b
))
165 return ((unsigned char)git__tolower(*a
) - (unsigned char)git__tolower(*b
));
168 int git__strcasesort_cmp(const char *a
, const char *b
)
174 if (git__tolower(*a
) != git__tolower(*b
))
176 /* use case in sort order even if not in equivalence */
178 cmp
= (int)(*(const uint8_t *)a
) - (int)(*(const uint8_t *)b
);
185 return (unsigned char)git__tolower(*a
) - (unsigned char)git__tolower(*b
);
190 int git__strncasecmp(const char *a
, const char *b
, size_t sz
)
195 al
= (unsigned char)git__tolower(*a
);
196 bl
= (unsigned char)git__tolower(*b
);
198 } while (--sz
&& al
&& al
== bl
);
203 void git__strntolower(char *str
, size_t len
)
207 for (i
= 0; i
< len
; ++i
) {
208 str
[i
] = (char)git__tolower(str
[i
]);
212 void git__strtolower(char *str
)
214 git__strntolower(str
, strlen(str
));
217 GIT_INLINE(int) prefixcmp(const char *str
, size_t str_n
, const char *prefix
, bool icase
)
222 s
= (unsigned char)*str
++;
223 p
= (unsigned char)*prefix
++;
237 return (0 - *prefix
);
240 int git__prefixcmp(const char *str
, const char *prefix
)
256 int git__prefixncmp(const char *str
, size_t str_n
, const char *prefix
)
258 return prefixcmp(str
, str_n
, prefix
, false);
261 int git__prefixcmp_icase(const char *str
, const char *prefix
)
263 return prefixcmp(str
, SIZE_MAX
, prefix
, true);
266 int git__prefixncmp_icase(const char *str
, size_t str_n
, const char *prefix
)
268 return prefixcmp(str
, str_n
, prefix
, true);
271 int git__suffixcmp(const char *str
, const char *suffix
)
273 size_t a
= strlen(str
);
274 size_t b
= strlen(suffix
);
277 return strcmp(str
+ (a
- b
), suffix
);
280 char *git__strtok(char **end
, const char *sep
)
284 while (*ptr
&& strchr(sep
, *ptr
))
291 while (**end
&& !strchr(sep
, **end
))
305 /* Similar to strtok, but does not collapse repeated tokens. */
306 char *git__strsep(char **end
, const char *sep
)
308 char *start
= *end
, *ptr
= *end
;
310 while (*ptr
&& !strchr(sep
, *ptr
))
323 size_t git__linenlen(const char *buffer
, size_t buffer_len
)
325 char *nl
= memchr(buffer
, '\n', buffer_len
);
326 return nl
? (size_t)(nl
- buffer
) + 1 : buffer_len
;
330 * Adapted Not So Naive algorithm from http://www-igm.univ-mlv.fr/~lecroq/string/
332 const void * git__memmem(const void *haystack
, size_t haystacklen
,
333 const void *needle
, size_t needlelen
)
338 if (needlelen
> haystacklen
|| !haystacklen
|| !needlelen
)
341 h
= (const char *) haystack
,
342 n
= (const char *) needle
;
345 return memchr(haystack
, *n
, haystacklen
);
356 while (j
<= haystacklen
- needlelen
) {
357 if (n
[1] != h
[j
+ 1]) {
360 if (memcmp(n
+ 2, h
+ j
+ 2, needlelen
- 2) == 0 &&
370 void git__hexdump(const char *buffer
, size_t len
)
372 static const size_t LINE_WIDTH
= 16;
374 size_t line_count
, last_line
, i
, j
;
377 line_count
= (len
/ LINE_WIDTH
);
378 last_line
= (len
% LINE_WIDTH
);
380 for (i
= 0; i
< line_count
; ++i
) {
381 printf("%08" PRIxZ
" ", (i
* LINE_WIDTH
));
383 line
= buffer
+ (i
* LINE_WIDTH
);
384 for (j
= 0; j
< LINE_WIDTH
; ++j
, ++line
) {
385 printf("%02x ", (unsigned char)*line
& 0xFF);
387 if (j
== (LINE_WIDTH
/ 2))
393 line
= buffer
+ (i
* LINE_WIDTH
);
394 for (j
= 0; j
< LINE_WIDTH
; ++j
, ++line
)
395 printf("%c", (*line
>= 32 && *line
<= 126) ? *line
: '.');
401 printf("%08" PRIxZ
" ", (line_count
* LINE_WIDTH
));
403 line
= buffer
+ (line_count
* LINE_WIDTH
);
404 for (j
= 0; j
< last_line
; ++j
, ++line
) {
405 printf("%02x ", (unsigned char)*line
& 0xFF);
407 if (j
== (LINE_WIDTH
/ 2))
411 if (j
< (LINE_WIDTH
/ 2))
413 for (j
= 0; j
< (LINE_WIDTH
- last_line
); ++j
)
418 line
= buffer
+ (line_count
* LINE_WIDTH
);
419 for (j
= 0; j
< last_line
; ++j
, ++line
)
420 printf("%c", (*line
>= 32 && *line
<= 126) ? *line
: '.');
428 #ifdef GIT_LEGACY_HASH
429 uint32_t git__hash(const void *key
, int len
, unsigned int seed
)
431 const uint32_t m
= 0x5bd1e995;
433 uint32_t h
= seed
^ len
;
435 const unsigned char *data
= (const unsigned char *)key
;
438 uint32_t k
= *(uint32_t *)data
;
452 case 3: h
^= data
[2] << 16;
453 case 2: h
^= data
[1] << 8;
454 case 1: h
^= data
[0];
466 Cross-platform version of Murmurhash3
467 http://code.google.com/p/smhasher/wiki/MurmurHash3
468 by Austin Appleby (aappleby@gmail.com)
470 This code is on the public domain.
472 uint32_t git__hash(const void *key
, int len
, uint32_t seed
)
475 #define MURMUR_BLOCK() {\
477 k1 = git__rotl(k1,11);\
480 h1 = h1*3 + 0x52dce729;\
481 c1 = c1*5 + 0x7b7d159c;\
482 c2 = c2*5 + 0x6bce6396;\
485 const uint8_t *data
= (const uint8_t*)key
;
486 const int nblocks
= len
/ 4;
488 const uint32_t *blocks
= (const uint32_t *)(data
+ nblocks
* 4);
489 const uint8_t *tail
= (const uint8_t *)(data
+ nblocks
* 4);
491 uint32_t h1
= 0x971e137b ^ seed
;
494 uint32_t c1
= 0x95543787;
495 uint32_t c2
= 0x2ad7eb25;
499 for (i
= -nblocks
; i
; i
++) {
507 case 3: k1
^= tail
[2] << 16;
509 case 2: k1
^= tail
[1] << 8;
511 case 1: k1
^= tail
[0];
527 * A modified `bsearch` from the BSD glibc.
529 * Copyright (c) 1990 Regents of the University of California.
530 * All rights reserved.
531 * Redistribution and use in source and binary forms, with or without
532 * modification, are permitted provided that the following conditions
534 * 1. Redistributions of source code must retain the above copyright
535 * notice, this list of conditions and the following disclaimer.
536 * 2. Redistributions in binary form must reproduce the above copyright
537 * notice, this list of conditions and the following disclaimer in the
538 * documentation and/or other materials provided with the distribution.
539 * 3. [rescinded 22 July 1999]
540 * 4. Neither the name of the University nor the names of its contributors
541 * may be used to endorse or promote products derived from this software
542 * without specific prior written permission.
544 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
545 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
546 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
547 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
548 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
549 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
550 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
551 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
552 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
553 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
560 int (*compare
)(const void *, const void *),
565 void **part
, **base
= array
;
567 for (lim
= array_len
; lim
!= 0; lim
>>= 1) {
568 part
= base
+ (lim
>> 1);
569 cmp
= (*compare
)(key
, *part
);
574 if (cmp
> 0) { /* key > p; take right partition */
577 } /* else take left partition */
581 *position
= (base
- array
);
583 return (cmp
== 0) ? 0 : GIT_ENOTFOUND
;
590 int (*compare_r
)(const void *, const void *, void *),
596 void **part
, **base
= array
;
598 for (lim
= array_len
; lim
!= 0; lim
>>= 1) {
599 part
= base
+ (lim
>> 1);
600 cmp
= (*compare_r
)(key
, *part
, payload
);
605 if (cmp
> 0) { /* key > p; take right partition */
608 } /* else take left partition */
612 *position
= (base
- array
);
614 return (cmp
== 0) ? 0 : GIT_ENOTFOUND
;
620 * We don't want direct pointers to the CRT on Windows, we may
621 * get stdcall conflicts.
623 int git__strcmp_cb(const void *a
, const void *b
)
625 return strcmp((const char *)a
, (const char *)b
);
628 int git__strcasecmp_cb(const void *a
, const void *b
)
630 return strcasecmp((const char *)a
, (const char *)b
);
633 int git__parse_bool(int *out
, const char *value
)
635 /* A missing value means true */
637 !strcasecmp(value
, "true") ||
638 !strcasecmp(value
, "yes") ||
639 !strcasecmp(value
, "on")) {
643 if (!strcasecmp(value
, "false") ||
644 !strcasecmp(value
, "no") ||
645 !strcasecmp(value
, "off") ||
654 size_t git__unescape(char *str
)
656 char *scan
, *pos
= str
;
661 for (scan
= str
; *scan
; pos
++, scan
++) {
662 if (*scan
== '\\' && *(scan
+ 1) != '\0')
663 scan
++; /* skip '\' but include next char */
675 #if defined(HAVE_QSORT_S) || defined(HAVE_QSORT_R_BSD)
681 static int GIT_STDLIB_CALL
git__qsort_r_glue_cmp(
682 void *payload
, const void *a
, const void *b
)
684 git__qsort_r_glue
*glue
= payload
;
685 return glue
->cmp(a
, b
, glue
->payload
);
690 #if !defined(HAVE_QSORT_R_BSD) && \
691 !defined(HAVE_QSORT_R_GNU) && \
692 !defined(HAVE_QSORT_S)
693 static void swap(uint8_t *a
, uint8_t *b
, size_t elsize
)
698 size_t n
= elsize
< sizeof(tmp
) ? elsize
: sizeof(tmp
);
699 memcpy(tmp
, a
+ elsize
- n
, n
);
700 memcpy(a
+ elsize
- n
, b
+ elsize
- n
, n
);
701 memcpy(b
+ elsize
- n
, tmp
, n
);
706 static void insertsort(
707 void *els
, size_t nel
, size_t elsize
,
708 git__sort_r_cmp cmp
, void *payload
)
711 uint8_t *end
= base
+ nel
* elsize
;
714 for (i
= base
+ elsize
; i
< end
; i
+= elsize
)
715 for (j
= i
; j
> base
&& cmp(j
, j
- elsize
, payload
) < 0; j
-= elsize
)
716 swap(j
, j
- elsize
, elsize
);
721 void *els
, size_t nel
, size_t elsize
, git__sort_r_cmp cmp
, void *payload
)
723 #if defined(HAVE_QSORT_R_BSD)
724 git__qsort_r_glue glue
= { cmp
, payload
};
725 qsort_r(els
, nel
, elsize
, &glue
, git__qsort_r_glue_cmp
);
726 #elif defined(HAVE_QSORT_R_GNU)
727 qsort_r(els
, nel
, elsize
, cmp
, payload
);
728 #elif defined(HAVE_QSORT_S)
729 git__qsort_r_glue glue
= { cmp
, payload
};
730 qsort_s(els
, nel
, elsize
, git__qsort_r_glue_cmp
, &glue
);
732 insertsort(els
, nel
, elsize
, cmp
, payload
);
737 * git__utf8_iterate is taken from the utf8proc project,
738 * http://www.public-software-group.org/utf8proc
740 * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
742 * Permission is hereby granted, free of charge, to any person obtaining a
743 * copy of this software and associated documentation files (the ""Software""),
744 * to deal in the Software without restriction, including without limitation
745 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
746 * and/or sell copies of the Software, and to permit persons to whom the
747 * Software is furnished to do so, subject to the following conditions:
749 * The above copyright notice and this permission notice shall be included in
750 * all copies or substantial portions of the Software.
752 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
753 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
754 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
755 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
756 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
757 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
758 * DEALINGS IN THE SOFTWARE.
761 static const int8_t utf8proc_utf8class
[256] = {
762 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
763 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
764 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
765 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
766 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
767 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
768 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
769 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
770 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
771 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
772 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
773 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
774 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
775 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
776 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
777 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0
780 static int util_utf8_charlen(const uint8_t *str
, size_t str_len
)
784 length
= utf8proc_utf8class
[str
[0]];
788 if (str_len
> 0 && length
> str_len
)
791 for (i
= 1; i
< length
; i
++) {
792 if ((str
[i
] & 0xC0) != 0x80)
799 int git__utf8_iterate(const uint8_t *str
, int str_len
, int32_t *dst
)
805 length
= util_utf8_charlen(str
, str_len
);
814 uc
= ((str
[0] & 0x1F) << 6) + (str
[1] & 0x3F);
815 if (uc
< 0x80) uc
= -1;
818 uc
= ((str
[0] & 0x0F) << 12) + ((str
[1] & 0x3F) << 6)
820 if (uc
< 0x800 || (uc
>= 0xD800 && uc
< 0xE000) ||
821 (uc
>= 0xFDD0 && uc
< 0xFDF0)) uc
= -1;
824 uc
= ((str
[0] & 0x07) << 18) + ((str
[1] & 0x3F) << 12)
825 + ((str
[2] & 0x3F) << 6) + (str
[3] & 0x3F);
826 if (uc
< 0x10000 || uc
>= 0x110000) uc
= -1;
830 if (uc
< 0 || ((uc
& 0xFFFF) >= 0xFFFE))
837 size_t git__utf8_valid_buf_length(const uint8_t *str
, size_t str_len
)
841 while (offset
< str_len
) {
842 int length
= util_utf8_charlen(str
+ offset
, str_len
- offset
);
854 int git__getenv(git_buf
*out
, const char *name
)
856 wchar_t *wide_name
= NULL
, *wide_value
= NULL
;
862 if (git__utf8_to_16_alloc(&wide_name
, name
) < 0)
865 if ((value_len
= GetEnvironmentVariableW(wide_name
, NULL
, 0)) > 0) {
866 wide_value
= git__malloc(value_len
* sizeof(wchar_t));
867 GIT_ERROR_CHECK_ALLOC(wide_value
);
869 value_len
= GetEnvironmentVariableW(wide_name
, wide_value
, value_len
);
873 error
= git_buf_put_w(out
, wide_value
, value_len
);
874 else if (GetLastError() == ERROR_ENVVAR_NOT_FOUND
)
875 error
= GIT_ENOTFOUND
;
877 git_error_set(GIT_ERROR_OS
, "could not read environment variable '%s'", name
);
879 git__free(wide_name
);
880 git__free(wide_value
);
884 int git__getenv(git_buf
*out
, const char *name
)
886 const char *val
= getenv(name
);
891 return GIT_ENOTFOUND
;
893 return git_buf_puts(out
, val
);