Skip to content

Commit

Permalink
Implement strncmp and memcmp. Fixes #697 (#698)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamphaus authored and elliotchance committed May 4, 2018
1 parent e7852ca commit 5f6253e
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
38 changes: 38 additions & 0 deletions noarch/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)]))
}
6 changes: 6 additions & 0 deletions program/function_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
60 changes: 58 additions & 2 deletions tests/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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";
Expand All @@ -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);
Expand Down Expand Up @@ -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();
}

0 comments on commit 5f6253e

Please sign in to comment.