Tue, 04 Oct 2022 18:49:14 +0200
add zero-termination guarantees
src/cx/string.h | file | annotate | diff | comparison | revisions | |
test/test_string.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/cx/string.h Tue Sep 20 10:37:29 2022 +0200 1.2 +++ b/src/cx/string.h Tue Oct 04 18:49:14 2022 +0200 1.3 @@ -241,6 +241,7 @@ 1.4 * So developers \em must pass the return value to cx_strfree() eventually. 1.5 * 1.6 * \note It is guaranteed that there is only one allocation. 1.7 + * It is also guaranteed that the returned string is zero-terminated. 1.8 * 1.9 * @param alloc the allocator to use 1.10 * @param count the total number of strings to concatenate 1.11 @@ -260,6 +261,9 @@ 1.12 * The resulting string will be allocated by standard \c malloc(). 1.13 * So developers \em must pass the return value to cx_strfree() eventually. 1.14 * 1.15 + * \note It is guaranteed that there is only one allocation. 1.16 + * It is also guaranteed that the returned string is zero-terminated. 1.17 + * 1.18 * @param count the total number of strings to concatenate 1.19 * @param ... all strings 1.20 * @return the concatenated string 1.21 @@ -608,8 +612,7 @@ 1.22 * 1.23 * The new string will contain a copy allocated by \p allocator. 1.24 * 1.25 - * \note The returned string is guaranteed to be zero-terminated and can safely 1.26 - * be passed to other APIs. 1.27 + * \note The returned string is guaranteed to be zero-terminated. 1.28 * 1.29 * @param allocator the allocator to use 1.30 * @param string the string to duplicate 1.31 @@ -628,8 +631,7 @@ 1.32 * The new string will contain a copy allocated by standard 1.33 * \c malloc(). So developers \em must pass the return value to cx_strfree(). 1.34 * 1.35 - * \note The returned string is guaranteed to be zero-terminated and can safely 1.36 - * be passed to other APIs. 1.37 + * \note The returned string is guaranteed to be zero-terminated. 1.38 * 1.39 * @param string the string to duplicate 1.40 * @return a duplicate of the string 1.41 @@ -743,7 +745,8 @@ 1.42 * The pattern is taken literally and is no regular expression. 1.43 * Replaces at most \p replmax occurrences. 1.44 * 1.45 - * The returned string will be allocated by \p allocator. 1.46 + * The returned string will be allocated by \p allocator and is guaranteed 1.47 + * to be zero-terminated. 1.48 * 1.49 * If allocation fails, or the input string is empty, 1.50 * the returned string will be empty. 1.51 @@ -770,8 +773,8 @@ 1.52 * The pattern is taken literally and is no regular expression. 1.53 * Replaces at most \p replmax occurrences. 1.54 * 1.55 - * The returned string will be allocated by \c malloc() and \em must be passed 1.56 - * to cx_strfree() eventually. 1.57 + * The returned string will be allocated by \c malloc() and is guaranteed 1.58 + * to be zero-terminated. 1.59 * 1.60 * If allocation fails, or the input string is empty, 1.61 * the returned string will be empty. 1.62 @@ -790,7 +793,8 @@ 1.63 * 1.64 * The pattern is taken literally and is no regular expression. 1.65 * 1.66 - * The returned string will be allocated by \p allocator. 1.67 + * The returned string will be allocated by \p allocator and is guaranteed 1.68 + * to be zero-terminated. 1.69 * 1.70 * If allocation fails, or the input string is empty, 1.71 * the returned string will be empty. 1.72 @@ -810,8 +814,8 @@ 1.73 * The pattern is taken literally and is no regular expression. 1.74 * Replaces at most \p replmax occurrences. 1.75 * 1.76 - * The returned string will be allocated by \c malloc() and \em must be passed 1.77 - * to cx_strfree() eventually. 1.78 + * The returned string will be allocated by \c malloc() and is guaranteed 1.79 + * to be zero-terminated. 1.80 * 1.81 * If allocation fails, or the input string is empty, 1.82 * the returned string will be empty.
2.1 --- a/test/test_string.cpp Tue Sep 20 10:37:29 2022 +0200 2.2 +++ b/test/test_string.cpp Tue Oct 04 18:49:14 2022 +0200 2.3 @@ -31,6 +31,8 @@ 2.4 2.5 #include <gtest/gtest.h> 2.6 2.7 +#define EXPECT_ZERO_TERMINATED(str) EXPECT_EQ((str).ptr[(str).length], '\0') 2.8 + 2.9 TEST(String, construct) { 2.10 cxstring s1 = cx_str("1234"); 2.11 cxstring s2 = cx_strn("abcd", 2); 2.12 @@ -55,6 +57,22 @@ 2.13 EXPECT_TRUE(alloc.verify()); 2.14 } 2.15 2.16 +TEST(String, strdup) { 2.17 + cxstring str = CX_STR("test"); 2.18 + cxmutstr dup = cx_strdup(str); 2.19 + ASSERT_EQ(dup.length, str.length); 2.20 + EXPECT_STREQ(dup.ptr, str.ptr); 2.21 + EXPECT_ZERO_TERMINATED(dup); 2.22 + cx_strfree(&dup); 2.23 + 2.24 + str.length = 2; 2.25 + dup = cx_strdup(str); 2.26 + ASSERT_EQ(dup.length, str.length); 2.27 + EXPECT_STREQ(dup.ptr, "te"); 2.28 + EXPECT_ZERO_TERMINATED(dup); 2.29 + cx_strfree(&dup); 2.30 +} 2.31 + 2.32 TEST(String, strlen) { 2.33 cxstring s1 = CX_STR("1234"); 2.34 cxstring s2 = CX_STR(".:.:."); 2.35 @@ -210,7 +228,6 @@ 2.36 EXPECT_GT(cx_strcasecmp(str, cx_str("compare")), 0); 2.37 } 2.38 2.39 - 2.40 TEST(String, strcat) { 2.41 cxstring s1 = CX_STR("12"); 2.42 cxstring s2 = CX_STR("34"); 2.43 @@ -221,18 +238,22 @@ 2.44 2.45 cxmutstr t1 = cx_strcat_a(&alloc, 2, s1, s2); 2.46 EXPECT_EQ(cx_strcmp(cx_strcast(t1), cx_str("1234")), 0); 2.47 + EXPECT_ZERO_TERMINATED(t1); 2.48 cx_strfree_a(&alloc, &t1); 2.49 2.50 cxmutstr t2 = cx_strcat_a(&alloc, 3, s1, s2, s3); 2.51 EXPECT_EQ(cx_strcmp(cx_strcast(t2), cx_str("123456")), 0); 2.52 + EXPECT_ZERO_TERMINATED(t2); 2.53 cx_strfree_a(&alloc, &t2); 2.54 2.55 cxmutstr t3 = cx_strcat_a(&alloc, 6, s1, sn, s2, sn, s3, sn); 2.56 EXPECT_EQ(cx_strcmp(cx_strcast(t3), cx_str("123456")), 0); 2.57 + EXPECT_ZERO_TERMINATED(t3); 2.58 cx_strfree_a(&alloc, &t3); 2.59 2.60 cxmutstr t4 = cx_strcat_a(&alloc, 2, sn, sn); 2.61 EXPECT_EQ(cx_strcmp(cx_strcast(t4), cx_str("")), 0); 2.62 + EXPECT_ZERO_TERMINATED(t4); 2.63 cx_strfree_a(&alloc, &t4); 2.64 2.65 EXPECT_TRUE(alloc.verify()); 2.66 @@ -524,63 +545,75 @@ 2.67 cxstring csstr = CX_STR("test AB ab TEST xyz"); 2.68 2.69 cxmutstr repl = cx_strreplace(str, cx_str("abab"), cx_str("muchlonger")); 2.70 - cxstring expected = CX_STR("test muchlongerab string aba"); 2.71 + auto expected = "test muchlongerab string aba"; 2.72 2.73 cxmutstr repln = cx_strreplacen(str, cx_str("ab"), cx_str("c"), 2); 2.74 - cxstring expectedn = CX_STR("test ccab string aba"); 2.75 + auto expectedn = "test ccab string aba"; 2.76 2.77 cxmutstr longrepl = cx_strreplace(longstr, cx_str("a"), cx_str("z")); 2.78 - cxstring longexpect = CX_STR( 2.79 - "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd"); 2.80 + auto longexpect = "xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzcd"; 2.81 2.82 cxmutstr replnotrail = cx_strreplace(notrail, cx_str("ab"), cx_str("z")); 2.83 - cxstring notrailexpect = CX_STR("test zz"); 2.84 + auto notrailexpect = "test zz"; 2.85 2.86 cxmutstr repleq = cx_strreplace(str, str, cx_str("hello")); 2.87 - cxstring eqexpect = CX_STR("hello"); 2.88 + auto eqexpect = "hello"; 2.89 2.90 cxmutstr replempty1 = cx_strreplace(empty, cx_str("ab"), cx_str("c")); // expect: empty 2.91 cxmutstr replempty2 = cx_strreplace(str, cx_str("abab"), empty); 2.92 - cxstring emptyexpect2 = CX_STR("test ab string aba"); 2.93 + auto emptyexpect2 = "test ab string aba"; 2.94 2.95 cxmutstr replpre = cx_strreplace(str, cx_str("test "), cx_str("TEST ")); 2.96 - cxstring preexpected = CX_STR("TEST ababab string aba"); 2.97 + auto preexpected = "TEST ababab string aba"; 2.98 2.99 cxmutstr replan1 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 1); 2.100 - cxstring an1expected = CX_STR("xaaaaaaaaa"); 2.101 + auto an1expected = "xaaaaaaaaa"; 2.102 2.103 cxmutstr replan4 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 4); 2.104 - cxstring an4expected = CX_STR("xxxxaaaaaa"); 2.105 + auto an4expected = "xxxxaaaaaa"; 2.106 2.107 cxmutstr replan9 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 9); 2.108 - cxstring an9expected = CX_STR("xxxxxxxxxa"); 2.109 + auto an9expected = "xxxxxxxxxa"; 2.110 2.111 cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10); 2.112 - cxstring an10expected = CX_STR("xxxxxxxxxx"); 2.113 + auto an10expected = "xxxxxxxxxx"; 2.114 2.115 cxmutstr replcs1 = cx_strreplace(csstr, cx_str("AB"), cx_str("*")); 2.116 - cxstring cs1expected = CX_STR("test * ab TEST xyz"); 2.117 + auto cs1expected = "test * ab TEST xyz"; 2.118 2.119 cxmutstr replcs2 = cx_strreplace(csstr, cx_str("test"), cx_str("TEST")); 2.120 - cxstring cs2expected = CX_STR("TEST AB ab TEST xyz"); 2.121 + auto cs2expected = "TEST AB ab TEST xyz"; 2.122 2.123 2.124 EXPECT_NE(repl.ptr, str.ptr); 2.125 - EXPECT_EQ(cx_strcmp(cx_strcast(repl), expected), 0); 2.126 - EXPECT_NE(repln.ptr, str.ptr); 2.127 - EXPECT_EQ(cx_strcmp(cx_strcast(repln), expectedn), 0); 2.128 - EXPECT_EQ(cx_strcmp(cx_strcast(longrepl), longexpect), 0); 2.129 - EXPECT_EQ(cx_strcmp(cx_strcast(replnotrail), notrailexpect), 0); 2.130 - EXPECT_EQ(cx_strcmp(cx_strcast(repleq), eqexpect), 0); 2.131 - EXPECT_EQ(cx_strcmp(cx_strcast(replempty1), empty), 0); 2.132 - EXPECT_EQ(cx_strcmp(cx_strcast(replempty2), emptyexpect2), 0); 2.133 - EXPECT_EQ(cx_strcmp(cx_strcast(replpre), preexpected), 0); 2.134 - EXPECT_EQ(cx_strcmp(cx_strcast(replan1), an1expected), 0); 2.135 - EXPECT_EQ(cx_strcmp(cx_strcast(replan4), an4expected), 0); 2.136 - EXPECT_EQ(cx_strcmp(cx_strcast(replan9), an9expected), 0); 2.137 - EXPECT_EQ(cx_strcmp(cx_strcast(replan10), an10expected), 0); 2.138 - EXPECT_EQ(cx_strcmp(cx_strcast(replcs1), cs1expected), 0); 2.139 - EXPECT_EQ(cx_strcmp(cx_strcast(replcs2), cs2expected), 0); 2.140 + EXPECT_ZERO_TERMINATED(repl); 2.141 + EXPECT_STREQ(repl.ptr, expected); 2.142 + EXPECT_ZERO_TERMINATED(repln); 2.143 + EXPECT_STREQ(repln.ptr, expectedn); 2.144 + EXPECT_ZERO_TERMINATED(longrepl); 2.145 + EXPECT_STREQ(longrepl.ptr, longexpect); 2.146 + EXPECT_ZERO_TERMINATED(replnotrail); 2.147 + EXPECT_STREQ(replnotrail.ptr, notrailexpect); 2.148 + EXPECT_ZERO_TERMINATED(repleq); 2.149 + EXPECT_STREQ(repleq.ptr, eqexpect); 2.150 + EXPECT_ZERO_TERMINATED(replempty1); 2.151 + EXPECT_STREQ(replempty1.ptr, ""); 2.152 + EXPECT_ZERO_TERMINATED(replempty2); 2.153 + EXPECT_STREQ(replempty2.ptr, emptyexpect2); 2.154 + EXPECT_ZERO_TERMINATED(replpre); 2.155 + EXPECT_STREQ(replpre.ptr, preexpected); 2.156 + EXPECT_ZERO_TERMINATED(replan1); 2.157 + EXPECT_STREQ(replan1.ptr, an1expected); 2.158 + EXPECT_ZERO_TERMINATED(replan4); 2.159 + EXPECT_STREQ(replan4.ptr, an4expected); 2.160 + EXPECT_ZERO_TERMINATED(replan9); 2.161 + EXPECT_STREQ(replan9.ptr, an9expected); 2.162 + EXPECT_ZERO_TERMINATED(replan10); 2.163 + EXPECT_STREQ(replan10.ptr, an10expected); 2.164 + EXPECT_ZERO_TERMINATED(replcs1); 2.165 + EXPECT_STREQ(replcs1.ptr, cs1expected); 2.166 + EXPECT_ZERO_TERMINATED(replcs2); 2.167 + EXPECT_STREQ(replcs2.ptr, cs2expected); 2.168 2.169 cx_strfree(&repl); 2.170 cx_strfree(&repln);