diff --git a/noarch/string.go b/noarch/string.go index b968bc624..cb85824f3 100644 --- a/noarch/string.go +++ b/noarch/string.go @@ -82,6 +82,24 @@ func Strcmp(str1, str2 []byte) int32 { return int32(bytes.Compare([]byte(CStringToString(str1)), []byte(CStringToString(str2)))) } +// Strncmp - compare two strings +// Compares the C string str1 to the C string str2 upto the first NULL character +// or n-th character whichever comes first. +func Strncmp(str1, str2 []byte, n int32) int32 { + a := []byte(CStringToString(str1)) + a = a[:int(min(int(n), len(a)))] + b := []byte(CStringToString(str2)) + b = b[:int(min(int(n), len(b)))] + return int32(bytes.Compare(a, b)) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + // Strchr - Locate first occurrence of character in string // See: http://www.cplusplus.com/reference/cstring/strchr/ func Strchr(str []byte, ch int32) []byte { @@ -140,3 +158,23 @@ func Memcpy(dst interface{}, src interface{}, size int32) interface{} { copy(bDst[:size], bSrc[:size]) return dst } + +// Memcmp compares two binary arrays upto n bytes. +// Different from strncmp, memcmp does not stop at the first NULL byte. +func Memcmp(src1, src2 interface{}, n int32) int32 { + v1 := reflect.ValueOf(src1).Type() + switch v1.Kind() { + case reflect.Slice, reflect.Array: + v1 = v1.Elem() + } + baseSize1 := int32(v1.Size()) + v2 := reflect.ValueOf(src2).Type() + switch v2.Kind() { + case reflect.Slice, reflect.Array: + v2 = v2.Elem() + } + baseSize2 := int32(v2.Size()) + b1 := *(*[]byte)(unsafe.Pointer(UnsafeSliceToSlice(src1, baseSize1, int32(1)))) + b2 := *(*[]byte)(unsafe.Pointer(UnsafeSliceToSlice(src2, baseSize2, int32(1)))) + return int32(bytes.Compare(b1[:int(n)], b2[:int(n)])) +} diff --git a/program/function_definition.go b/program/function_definition.go index 3258ef3a2..a79148955 100644 --- a/program/function_definition.go +++ b/program/function_definition.go @@ -182,6 +182,9 @@ var builtInFunctionDefinitions = map[string][]string{ // string.h "char* strcat(char *, const char *) -> noarch.Strcat", "int strcmp(const char *, const char *) -> noarch.Strcmp", + + // should be: "int strncmp(const char*, const char*, size_t) -> noarch.Strncmp", + "int strncmp(const char *, const char *, int) -> noarch.Strncmp", "char * strchr(char *, int) -> noarch.Strchr", "char* strcpy(const char*, char*) -> noarch.Strcpy", @@ -201,6 +204,9 @@ var builtInFunctionDefinitions = map[string][]string{ // should be: "void* memmove(void *, void *, size_t) -> noarch.Memcpy" "void* memmove(void *, void *, int) -> noarch.Memcpy", + // should be: "int memmove(const void *, const void *, size_t) -> noarch.Memcmp" + "int memcmp(void *, void *, int) -> noarch.Memcmp", + // darwin/string.h // should be: const char*, char*, size_t "char* __builtin___strcpy_chk(const char*, char*, int) -> darwin.BuiltinStrcpy", diff --git a/tests/string.c b/tests/string.c index ff55b7af2..ce9c570ac 100644 --- a/tests/string.c +++ b/tests/string.c @@ -8,7 +8,7 @@ typedef struct mem { int main() { - plan(60); + plan(70); diag("TODO: __builtin_object_size") // https://github.com/elliotchance/c2go/issues/359 @@ -113,6 +113,39 @@ int main() is_true(strcmp(a,b) < 0); } } + { + diag("strncmp"); + { + char* a = "ab"; + char* b = "ab"; + is_true(strncmp(a,b,10) == 0); + } + { + char* a = "bb"; + char* b = "ab"; + is_true(strncmp(a,b,10) > 0); + } + { + char* a = "ab"; + char* b = "bb"; + is_true(strncmp(a,b,10) < 0); + } + { + char* a = "aba"; + char* b = "ab"; + is_true(strncmp(a,b,10) > 0); + } + { + char* a = "ab"; + char* b = "aba"; + is_true(strncmp(a,b,10) < 0); + } + { + char* a = "aba"; + char* b = "abc"; + is_true(strncmp(a,b,2) == 0); + } + } { diag("strchr"); char str[] = "This is a sample string"; @@ -132,7 +165,7 @@ int main() char *dest2; char *dest3; dest2 = (char*) memset(dest1, 'a', 4); - dest1[5] = '\0'; + dest1[4] = '\0'; is_streq(dest1, "aaaa"); is_streq(dest2, "aaaa"); dest3 = (char*) memset(&dest2[1], 'b', 2); @@ -212,6 +245,29 @@ int main() is_eq(dest7[1].a, 0); is_eq(dest7[1].b, 0.0); } + { + diag("memcmp"); + { + char* a = "ab\0c"; + char* b = "ab\0c"; + is_true(memcmp(a,b,4) == 0); + } + { + char* a = "ab\0a"; + char* b = "ab\0c"; + is_true(memcmp(a,b,4) < 0); + } + { + char* a = "ab\0c"; + char* b = "ab\0a"; + is_true(memcmp(a,b,4) > 0); + } + { + char* a = "ab\0c"; + char* b = "ab\0a"; + is_true(memcmp(a,b,3) == 0); + } + } done_testing(); }