diff --git a/contracts/eoslib/string.hpp b/contracts/eoslib/string.hpp index 030f4d72a9dc851ddf09d9368a5aa835ef3860c2..7b5374a4171da062dfabb7e986a55ab5ffc3990b 100644 --- a/contracts/eoslib/string.hpp +++ b/contracts/eoslib/string.hpp @@ -6,7 +6,21 @@ #include namespace eosio { - + /** + * @brief Count the length of null terminated string (excluding the null terminated symbol) + * Non-null terminated string need to be passed here, + * Otherwise it will not give the right length + * @param cstr - null terminated string + */ + inline uint32_t cstrlen(const char* cstr) { + uint32_t len = 0; + while(*cstr != '\0') { + len++; + cstr++; + } + return len; + } + class string { private: @@ -63,6 +77,21 @@ namespace eosio { } } + /** + * @brief Constructor for string literal + * Non-null terminated string need to be passed here, + * Otherwise it will have extraneous data + * @param cstr - null terminated string + */ + string(const char* cstr) { + size = cstrlen(cstr) + 1; + data = (char *)malloc(size * sizeof(char)); + memcpy(data, cstr, size * sizeof(char)); + own_memory = true; + refcount = (uint32_t*)malloc(sizeof(uint32_t)); + *refcount = 1; + } + // Destructor ~string() { release_data_if_needed(); @@ -131,6 +160,7 @@ namespace eosio { return *(data + index); } + // Assignment operator string& operator = (const string& obj) { if (this != &obj) { release_data_if_needed(); @@ -143,6 +173,23 @@ namespace eosio { return *this; } + /** + * @brief Assignment operator for string literal + * Non-null terminated string need to be passed here, + * Otherwise it will have extraneous data + * @param cstr - null terminated string + */ + string& operator = (const char* cstr) { + release_data_if_needed(); + size = cstrlen(cstr) + 1; + data = (char *)malloc(size * sizeof(char)); + memcpy(data, cstr, size * sizeof(char)); + own_memory = true; + refcount = (uint32_t*)malloc(sizeof(uint32_t)); + *refcount = 1; + return *this; + } + string& operator += (const string& str){ assert((size + str.size > size) && (size + str.size > str.size), "overflow"); diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp index f8db1354186bb8d3bcf95ec6083a2e9c6353cd52..785cceef62059e25b6c85a104614b5602ab245d5 100644 --- a/contracts/test_api/test_api.cpp +++ b/contracts/test_api/test_api.cpp @@ -111,6 +111,7 @@ extern "C" { WASM_TEST_HANDLER(test_string, print_unicode); WASM_TEST_HANDLER(test_string, valid_utf8); WASM_TEST_HANDLER(test_string, invalid_utf8); + WASM_TEST_HANDLER(test_string, string_literal); //unhandled test call WASM_TEST_ERROR_CODE = WASM_TEST_FAIL; diff --git a/contracts/test_api/test_api.hpp b/contracts/test_api/test_api.hpp index 1bad52b2513afcf7def57a2aa091a6624d0daebb..e7e2c926a074b5532fe2fe7b79f24d91a223468a 100644 --- a/contracts/test_api/test_api.hpp +++ b/contracts/test_api/test_api.hpp @@ -149,4 +149,5 @@ struct test_string { static unsigned int print_unicode(); static unsigned int valid_utf8(); static unsigned int invalid_utf8(); + static unsigned int string_literal(); }; diff --git a/contracts/test_api/test_string.cpp b/contracts/test_api/test_string.cpp index 0871bff9281e94cbd8698bc254c4024fc0256941..5519d89ba2d5c3d585ec8bc6288d6eec95987e51 100644 --- a/contracts/test_api/test_string.cpp +++ b/contracts/test_api/test_string.cpp @@ -291,7 +291,6 @@ unsigned int test_string::print_unicode() { return WASM_TEST_PASS; } - unsigned int test_string::valid_utf8() { // Roman alphabet is 1 byte UTF-8 char data[] = "abcdefghij"; @@ -330,3 +329,28 @@ unsigned int test_string::invalid_utf8() { return WASM_TEST_PASS; } + + +unsigned int test_string::string_literal() { + // Construct + char data1[] = "abcdefghij"; + char data2[] = "klmnopqrstuvwxyz"; + + eos::string str = "abcdefghij"; + + WASM_ASSERT( str.get_size() == 11, "data1 str.get_size() == 11" ); + for (uint8_t i = 0; i < 11; i++) { + WASM_ASSERT( str[i] == data1[i], "data1 str[i] == data1[i]" ); + } + WASM_ASSERT( str.is_own_memory() == true, "data1 str.is_own_memory() == true" ); + + str = "klmnopqrstuvwxyz"; + + WASM_ASSERT( str.get_size() == 17, "data2 str.get_size() == 17" ); + for (uint8_t i = 0; i < 17; i++) { + WASM_ASSERT( str[i] == data2[i], "data2 str[i] == data2[i]" ); + } + WASM_ASSERT( str.is_own_memory() == true, "data2 str.is_own_memory() == true" ); + + return WASM_TEST_PASS; +} diff --git a/tests/api_tests/api_tests.cpp b/tests/api_tests/api_tests.cpp index 41af4d82cb08c3f487c57930031c9f66ee91e85d..f222b23aa6ff03c82732a81960a0b25f8a3acea7 100644 --- a/tests/api_tests/api_tests.cpp +++ b/tests/api_tests/api_tests.cpp @@ -458,7 +458,8 @@ BOOST_FIXTURE_TEST_CASE(test_all, testing_fixture) BOOST_CHECK_EQUAL( capture[0], "你好,世界!"); BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "valid_utf8"), {}, {} ) == WASM_TEST_PASS, "test_string::valid_utf8()" ); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "invalid_utf8"), {}, {} ), fc::assert_exception, is_assert_exception ); - + BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "string_literal"), {}, {} ) == WASM_TEST_PASS, "test_string::string_literal()" ); + } FC_LOG_AND_RETHROW() } #define RUN_CODE_HANDLER_WITH_TRANSFER(account_name, test_wast) \