]>
git.proxmox.com Git - libgit2.git/blob - src/util.c
984a3d7804dba1dff4b02aab85431a73e531e955
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 void git_strarray_free(git_strarray
*array
)
32 for (i
= 0; i
< array
->count
; ++i
)
33 git__free(array
->strings
[i
]);
35 git__free(array
->strings
);
37 memset(array
, 0, sizeof(*array
));
40 int git_strarray_copy(git_strarray
*tgt
, const git_strarray
*src
)
46 memset(tgt
, 0, sizeof(*tgt
));
51 tgt
->strings
= git__calloc(src
->count
, sizeof(char *));
52 GIT_ERROR_CHECK_ALLOC(tgt
->strings
);
54 for (i
= 0; i
< src
->count
; ++i
) {
58 tgt
->strings
[tgt
->count
] = git__strdup(src
->strings
[i
]);
59 if (!tgt
->strings
[tgt
->count
]) {
60 git_strarray_free(tgt
);
61 memset(tgt
, 0, sizeof(*tgt
));
71 int git__strntol64(int64_t *result
, const char *nptr
, size_t nptr_len
, const char **endptr
, int base
)
75 int c
, ovfl
, v
, neg
, ndig
;
86 while (nptr_len
&& git__isspace(*p
))
95 if (*p
== '-' || *p
== '+') {
106 * Automatically detect the base if none was given to us.
107 * Right now, we assume that a number starting with '0x'
108 * is hexadecimal and a number starting with '0' is
114 else if (nptr_len
> 2 && (p
[1] == 'x' || p
[1] == 'X'))
120 if (base
< 0 || 36 < base
)
124 * Skip prefix of '0x'-prefixed hexadecimal numbers. There is no
125 * need to do the same for '0'-prefixed octal numbers as a
126 * leading '0' does not have any impact. Also, if we skip a
127 * leading '0' in such a string, then we may end up with no
128 * digits left and produce an error later on which isn't one.
130 if (base
== 16 && nptr_len
> 2 && p
[0] == '0' && (p
[1] == 'x' || p
[1] == 'X')) {
136 * Non-empty sequence of digits
138 for (; nptr_len
> 0; p
++,ndig
++,nptr_len
--) {
141 if ('0'<=c
&& c
<='9')
143 else if ('a'<=c
&& c
<='z')
145 else if ('A'<=c
&& c
<='Z')
150 if (n
> INT64_MAX
/ base
|| n
< INT64_MIN
/ base
) {
152 /* Keep on iterating until the end of this number */
156 if ((v
> 0 && nn
> INT64_MAX
- v
) ||
157 (v
< 0 && nn
< INT64_MIN
- v
)) {
159 /* Keep on iterating until the end of this number */
167 git_error_set(GIT_ERROR_INVALID
, "failed to convert string to long: not a number");
175 git_error_set(GIT_ERROR_INVALID
, "failed to convert string to long: overflow error");
183 int git__strntol32(int32_t *result
, const char *nptr
, size_t nptr_len
, const char **endptr
, int base
)
185 const char *tmp_endptr
;
190 if ((error
= git__strntol64(&tmp_long
, nptr
, nptr_len
, &tmp_endptr
, base
)) < 0)
193 tmp_int
= tmp_long
& 0xFFFFFFFF;
194 if (tmp_int
!= tmp_long
) {
195 int len
= tmp_endptr
- nptr
;
196 git_error_set(GIT_ERROR_INVALID
, "failed to convert: '%.*s' is too large", len
, nptr
);
202 *endptr
= tmp_endptr
;
207 int git__strcmp(const char *a
, const char *b
)
209 while (*a
&& *b
&& *a
== *b
)
211 return (int)(*(const unsigned char *)a
) - (int)(*(const unsigned char *)b
);
214 int git__strcasecmp(const char *a
, const char *b
)
216 while (*a
&& *b
&& git__tolower(*a
) == git__tolower(*b
))
218 return ((unsigned char)git__tolower(*a
) - (unsigned char)git__tolower(*b
));
221 int git__strcasesort_cmp(const char *a
, const char *b
)
227 if (git__tolower(*a
) != git__tolower(*b
))
229 /* use case in sort order even if not in equivalence */
231 cmp
= (int)(*(const uint8_t *)a
) - (int)(*(const uint8_t *)b
);
238 return (unsigned char)git__tolower(*a
) - (unsigned char)git__tolower(*b
);
243 int git__strncmp(const char *a
, const char *b
, size_t sz
)
245 while (sz
&& *a
&& *b
&& *a
== *b
)
249 return (int)(*(const unsigned char *)a
) - (int)(*(const unsigned char *)b
);
252 int git__strncasecmp(const char *a
, const char *b
, size_t sz
)
257 al
= (unsigned char)git__tolower(*a
);
258 bl
= (unsigned char)git__tolower(*b
);
260 } while (--sz
&& al
&& al
== bl
);
265 void git__strntolower(char *str
, size_t len
)
269 for (i
= 0; i
< len
; ++i
) {
270 str
[i
] = (char)git__tolower(str
[i
]);
274 void git__strtolower(char *str
)
276 git__strntolower(str
, strlen(str
));
279 GIT_INLINE(int) prefixcmp(const char *str
, size_t str_n
, const char *prefix
, bool icase
)
284 s
= (unsigned char)*str
++;
285 p
= (unsigned char)*prefix
++;
299 return (0 - *prefix
);
302 int git__prefixcmp(const char *str
, const char *prefix
)
304 return prefixcmp(str
, SIZE_MAX
, prefix
, false);
307 int git__prefixncmp(const char *str
, size_t str_n
, const char *prefix
)
309 return prefixcmp(str
, str_n
, prefix
, false);
312 int git__prefixcmp_icase(const char *str
, const char *prefix
)
314 return prefixcmp(str
, SIZE_MAX
, prefix
, true);
317 int git__prefixncmp_icase(const char *str
, size_t str_n
, const char *prefix
)
319 return prefixcmp(str
, str_n
, prefix
, true);
322 int git__suffixcmp(const char *str
, const char *suffix
)
324 size_t a
= strlen(str
);
325 size_t b
= strlen(suffix
);
328 return strcmp(str
+ (a
- b
), suffix
);
331 char *git__strtok(char **end
, const char *sep
)
335 while (*ptr
&& strchr(sep
, *ptr
))
342 while (**end
&& !strchr(sep
, **end
))
356 /* Similar to strtok, but does not collapse repeated tokens. */
357 char *git__strsep(char **end
, const char *sep
)
359 char *start
= *end
, *ptr
= *end
;
361 while (*ptr
&& !strchr(sep
, *ptr
))
374 size_t git__linenlen(const char *buffer
, size_t buffer_len
)
376 char *nl
= memchr(buffer
, '\n', buffer_len
);
377 return nl
? (size_t)(nl
- buffer
) + 1 : buffer_len
;
381 * Adapted Not So Naive algorithm from http://www-igm.univ-mlv.fr/~lecroq/string/
383 const void * git__memmem(const void *haystack
, size_t haystacklen
,
384 const void *needle
, size_t needlelen
)
389 if (needlelen
> haystacklen
|| !haystacklen
|| !needlelen
)
392 h
= (const char *) haystack
,
393 n
= (const char *) needle
;
396 return memchr(haystack
, *n
, haystacklen
);
407 while (j
<= haystacklen
- needlelen
) {
408 if (n
[1] != h
[j
+ 1]) {
411 if (memcmp(n
+ 2, h
+ j
+ 2, needlelen
- 2) == 0 &&
421 void git__hexdump(const char *buffer
, size_t len
)
423 static const size_t LINE_WIDTH
= 16;
425 size_t line_count
, last_line
, i
, j
;
428 line_count
= (len
/ LINE_WIDTH
);
429 last_line
= (len
% LINE_WIDTH
);
431 for (i
= 0; i
< line_count
; ++i
) {
432 line
= buffer
+ (i
* LINE_WIDTH
);
433 for (j
= 0; j
< LINE_WIDTH
; ++j
, ++line
)
434 printf("%02X ", (unsigned char)*line
& 0xFF);
438 line
= buffer
+ (i
* LINE_WIDTH
);
439 for (j
= 0; j
< LINE_WIDTH
; ++j
, ++line
)
440 printf("%c", (*line
>= 32 && *line
<= 126) ? *line
: '.');
447 line
= buffer
+ (line_count
* LINE_WIDTH
);
448 for (j
= 0; j
< last_line
; ++j
, ++line
)
449 printf("%02X ", (unsigned char)*line
& 0xFF);
451 for (j
= 0; j
< (LINE_WIDTH
- last_line
); ++j
)
456 line
= buffer
+ (line_count
* LINE_WIDTH
);
457 for (j
= 0; j
< last_line
; ++j
, ++line
)
458 printf("%c", (*line
>= 32 && *line
<= 126) ? *line
: '.');
466 #ifdef GIT_LEGACY_HASH
467 uint32_t git__hash(const void *key
, int len
, unsigned int seed
)
469 const uint32_t m
= 0x5bd1e995;
471 uint32_t h
= seed
^ len
;
473 const unsigned char *data
= (const unsigned char *)key
;
476 uint32_t k
= *(uint32_t *)data
;
490 case 3: h
^= data
[2] << 16;
491 case 2: h
^= data
[1] << 8;
492 case 1: h
^= data
[0];
504 Cross-platform version of Murmurhash3
505 http://code.google.com/p/smhasher/wiki/MurmurHash3
506 by Austin Appleby (aappleby@gmail.com)
508 This code is on the public domain.
510 uint32_t git__hash(const void *key
, int len
, uint32_t seed
)
513 #define MURMUR_BLOCK() {\
515 k1 = git__rotl(k1,11);\
518 h1 = h1*3 + 0x52dce729;\
519 c1 = c1*5 + 0x7b7d159c;\
520 c2 = c2*5 + 0x6bce6396;\
523 const uint8_t *data
= (const uint8_t*)key
;
524 const int nblocks
= len
/ 4;
526 const uint32_t *blocks
= (const uint32_t *)(data
+ nblocks
* 4);
527 const uint8_t *tail
= (const uint8_t *)(data
+ nblocks
* 4);
529 uint32_t h1
= 0x971e137b ^ seed
;
532 uint32_t c1
= 0x95543787;
533 uint32_t c2
= 0x2ad7eb25;
537 for (i
= -nblocks
; i
; i
++) {
545 case 3: k1
^= tail
[2] << 16;
547 case 2: k1
^= tail
[1] << 8;
549 case 1: k1
^= tail
[0];
565 * A modified `bsearch` from the BSD glibc.
567 * Copyright (c) 1990 Regents of the University of California.
568 * All rights reserved.
569 * Redistribution and use in source and binary forms, with or without
570 * modification, are permitted provided that the following conditions
572 * 1. Redistributions of source code must retain the above copyright
573 * notice, this list of conditions and the following disclaimer.
574 * 2. Redistributions in binary form must reproduce the above copyright
575 * notice, this list of conditions and the following disclaimer in the
576 * documentation and/or other materials provided with the distribution.
577 * 3. [rescinded 22 July 1999]
578 * 4. Neither the name of the University nor the names of its contributors
579 * may be used to endorse or promote products derived from this software
580 * without specific prior written permission.
582 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
583 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
584 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
585 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
586 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
587 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
588 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
589 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
590 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
591 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
598 int (*compare
)(const void *, const void *),
603 void **part
, **base
= array
;
605 for (lim
= array_len
; lim
!= 0; lim
>>= 1) {
606 part
= base
+ (lim
>> 1);
607 cmp
= (*compare
)(key
, *part
);
612 if (cmp
> 0) { /* key > p; take right partition */
615 } /* else take left partition */
619 *position
= (base
- array
);
621 return (cmp
== 0) ? 0 : GIT_ENOTFOUND
;
628 int (*compare_r
)(const void *, const void *, void *),
634 void **part
, **base
= array
;
636 for (lim
= array_len
; lim
!= 0; lim
>>= 1) {
637 part
= base
+ (lim
>> 1);
638 cmp
= (*compare_r
)(key
, *part
, payload
);
643 if (cmp
> 0) { /* key > p; take right partition */
646 } /* else take left partition */
650 *position
= (base
- array
);
652 return (cmp
== 0) ? 0 : GIT_ENOTFOUND
;
658 * We don't want direct pointers to the CRT on Windows, we may
659 * get stdcall conflicts.
661 int git__strcmp_cb(const void *a
, const void *b
)
663 return strcmp((const char *)a
, (const char *)b
);
666 int git__strcasecmp_cb(const void *a
, const void *b
)
668 return strcasecmp((const char *)a
, (const char *)b
);
671 int git__parse_bool(int *out
, const char *value
)
673 /* A missing value means true */
675 !strcasecmp(value
, "true") ||
676 !strcasecmp(value
, "yes") ||
677 !strcasecmp(value
, "on")) {
681 if (!strcasecmp(value
, "false") ||
682 !strcasecmp(value
, "no") ||
683 !strcasecmp(value
, "off") ||
692 size_t git__unescape(char *str
)
694 char *scan
, *pos
= str
;
699 for (scan
= str
; *scan
; pos
++, scan
++) {
700 if (*scan
== '\\' && *(scan
+ 1) != '\0')
701 scan
++; /* skip '\' but include next char */
713 #if defined(HAVE_QSORT_S) || defined(HAVE_QSORT_R_BSD)
719 static int GIT_STDLIB_CALL
git__qsort_r_glue_cmp(
720 void *payload
, const void *a
, const void *b
)
722 git__qsort_r_glue
*glue
= payload
;
723 return glue
->cmp(a
, b
, glue
->payload
);
728 void *els
, size_t nel
, size_t elsize
, git__sort_r_cmp cmp
, void *payload
)
730 #if defined(HAVE_QSORT_R_BSD)
731 git__qsort_r_glue glue
= { cmp
, payload
};
732 qsort_r(els
, nel
, elsize
, &glue
, git__qsort_r_glue_cmp
);
733 #elif defined(HAVE_QSORT_R_GNU)
734 qsort_r(els
, nel
, elsize
, cmp
, payload
);
735 #elif defined(HAVE_QSORT_S)
736 git__qsort_r_glue glue
= { cmp
, payload
};
737 qsort_s(els
, nel
, elsize
, git__qsort_r_glue_cmp
, &glue
);
739 git__insertsort_r(els
, nel
, elsize
, NULL
, cmp
, payload
);
743 void git__insertsort_r(
744 void *els
, size_t nel
, size_t elsize
, void *swapel
,
745 git__sort_r_cmp cmp
, void *payload
)
748 uint8_t *end
= base
+ nel
* elsize
;
750 bool freeswap
= !swapel
;
753 swapel
= git__malloc(elsize
);
755 for (i
= base
+ elsize
; i
< end
; i
+= elsize
)
756 for (j
= i
; j
> base
&& cmp(j
, j
- elsize
, payload
) < 0; j
-= elsize
) {
757 memcpy(swapel
, j
, elsize
);
758 memcpy(j
, j
- elsize
, elsize
);
759 memcpy(j
- elsize
, swapel
, elsize
);
767 * git__utf8_iterate is taken from the utf8proc project,
768 * http://www.public-software-group.org/utf8proc
770 * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
772 * Permission is hereby granted, free of charge, to any person obtaining a
773 * copy of this software and associated documentation files (the ""Software""),
774 * to deal in the Software without restriction, including without limitation
775 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
776 * and/or sell copies of the Software, and to permit persons to whom the
777 * Software is furnished to do so, subject to the following conditions:
779 * The above copyright notice and this permission notice shall be included in
780 * all copies or substantial portions of the Software.
782 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
783 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
784 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
785 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
786 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
787 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
788 * DEALINGS IN THE SOFTWARE.
791 static const int8_t utf8proc_utf8class
[256] = {
792 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
793 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
794 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
795 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
796 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
797 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
798 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
799 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
800 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
801 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
802 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
803 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
804 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
805 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
806 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
807 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0
810 int git__utf8_charlen(const uint8_t *str
, int str_len
)
814 length
= utf8proc_utf8class
[str
[0]];
818 if (str_len
>= 0 && length
> str_len
)
821 for (i
= 1; i
< length
; i
++) {
822 if ((str
[i
] & 0xC0) != 0x80)
829 int git__utf8_iterate(const uint8_t *str
, int str_len
, int32_t *dst
)
835 length
= git__utf8_charlen(str
, str_len
);
844 uc
= ((str
[0] & 0x1F) << 6) + (str
[1] & 0x3F);
845 if (uc
< 0x80) uc
= -1;
848 uc
= ((str
[0] & 0x0F) << 12) + ((str
[1] & 0x3F) << 6)
850 if (uc
< 0x800 || (uc
>= 0xD800 && uc
< 0xE000) ||
851 (uc
>= 0xFDD0 && uc
< 0xFDF0)) uc
= -1;
854 uc
= ((str
[0] & 0x07) << 18) + ((str
[1] & 0x3F) << 12)
855 + ((str
[2] & 0x3F) << 6) + (str
[3] & 0x3F);
856 if (uc
< 0x10000 || uc
>= 0x110000) uc
= -1;
860 if (uc
< 0 || ((uc
& 0xFFFF) >= 0xFFFE))
867 double git_time_monotonic(void)
872 size_t git__utf8_valid_buf_length(const uint8_t *str
, size_t str_len
)
876 while (offset
< str_len
) {
877 int length
= git__utf8_charlen(str
+ offset
, str_len
- offset
);
889 int git__getenv(git_buf
*out
, const char *name
)
891 wchar_t *wide_name
= NULL
, *wide_value
= NULL
;
897 if (git__utf8_to_16_alloc(&wide_name
, name
) < 0)
900 if ((value_len
= GetEnvironmentVariableW(wide_name
, NULL
, 0)) > 0) {
901 wide_value
= git__malloc(value_len
* sizeof(wchar_t));
902 GIT_ERROR_CHECK_ALLOC(wide_value
);
904 value_len
= GetEnvironmentVariableW(wide_name
, wide_value
, value_len
);
908 error
= git_buf_put_w(out
, wide_value
, value_len
);
909 else if (GetLastError() == ERROR_ENVVAR_NOT_FOUND
)
910 error
= GIT_ENOTFOUND
;
912 git_error_set(GIT_ERROR_OS
, "could not read environment variable '%s'", name
);
914 git__free(wide_name
);
915 git__free(wide_value
);
919 int git__getenv(git_buf
*out
, const char *name
)
921 const char *val
= getenv(name
);
926 return GIT_ENOTFOUND
;
928 return git_buf_puts(out
, val
);