Add a custom implementation of OpenBSD's strlcat and strlcpy.
This includes both an implementation and some basic unit tests for the above mentioned functions. svn-id: r48953
This commit is contained in:
parent
3b5bd3ada7
commit
388e4b65bf
3 changed files with 169 additions and 0 deletions
|
@ -739,4 +739,84 @@ String tag2string(uint32 tag) {
|
||||||
return Common::String(str);
|
return Common::String(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t strlcpy(char *dst, const char *src, size_t size) {
|
||||||
|
// Our backup of the source's start, we need this
|
||||||
|
// to calculate the source's length.
|
||||||
|
const char * const srcStart = src;
|
||||||
|
|
||||||
|
// In case a non-empty size was specified we
|
||||||
|
// copy over (size - 1) bytes at max.
|
||||||
|
if (size != 0) {
|
||||||
|
// Copy over (size - 1) bytes at max.
|
||||||
|
while (--size != 0) {
|
||||||
|
if ((*dst++ = *src) == 0)
|
||||||
|
break;
|
||||||
|
++src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case the source string was longer than the
|
||||||
|
// destination, we need to add a terminating
|
||||||
|
// zero.
|
||||||
|
if (size == 0)
|
||||||
|
*dst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the terminating zero of the source
|
||||||
|
// string, we need this to determin the length
|
||||||
|
// of the source string.
|
||||||
|
while (*src)
|
||||||
|
++src;
|
||||||
|
|
||||||
|
// Return the source string's length.
|
||||||
|
return src - srcStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strlcat(char *dst, const char *src, size_t size) {
|
||||||
|
// In case the destination buffer does not contain
|
||||||
|
// space for at least 1 character, we will just
|
||||||
|
// return the source string's length.
|
||||||
|
if (size == 0)
|
||||||
|
return strlen(src);
|
||||||
|
|
||||||
|
// Our backup of the source's start, we need this
|
||||||
|
// to calculate the source's length.
|
||||||
|
const char * const srcStart = src;
|
||||||
|
|
||||||
|
// Our backup of the destination's start, we need
|
||||||
|
// this to calculate the destination's length.
|
||||||
|
const char * const dstStart = dst;
|
||||||
|
|
||||||
|
// Search the end of the destination, but do not
|
||||||
|
// move past the terminating zero.
|
||||||
|
while (size-- != 0 && *dst != 0)
|
||||||
|
++dst;
|
||||||
|
|
||||||
|
// Calculate the destination's length;
|
||||||
|
const size_t dstLength = dst - dstStart;
|
||||||
|
|
||||||
|
// In case we reached the end of the destination
|
||||||
|
// buffer before we had a chance to append any
|
||||||
|
// characters we will just return the destination
|
||||||
|
// length plus the source string's length.
|
||||||
|
if (size == 0)
|
||||||
|
return dstLength + strlen(srcStart);
|
||||||
|
|
||||||
|
// Copy over all of the source that fits
|
||||||
|
// the destination buffer. We also need
|
||||||
|
// to take the terminating zero we will
|
||||||
|
// add into consideration.
|
||||||
|
while (size-- != 0 && *src != 0)
|
||||||
|
*dst++ = *src++;
|
||||||
|
*dst = 0;
|
||||||
|
|
||||||
|
// Move to the terminating zero of the source
|
||||||
|
// string, we need this to determin the length
|
||||||
|
// of the source string.
|
||||||
|
while (*src)
|
||||||
|
++src;
|
||||||
|
|
||||||
|
// Return the total length of the result string
|
||||||
|
return dstLength + (src - srcStart);
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Common
|
} // End of namespace Common
|
||||||
|
|
37
common/str.h
37
common/str.h
|
@ -325,6 +325,43 @@ bool matchString(const char *str, const char *pat, bool ignoreCase = false, bool
|
||||||
*/
|
*/
|
||||||
String tag2string(uint32 tag);
|
String tag2string(uint32 tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy up to size - 1 characters from src to dst and also zero terminate the
|
||||||
|
* result. Note that src must be a zero terminated string.
|
||||||
|
*
|
||||||
|
* In case size is zero this function just returns the length of the source
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* @note This is modeled after OpenBSD's strlcpy. See the manpage here:
|
||||||
|
* http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy
|
||||||
|
*
|
||||||
|
* @param dst The destination buffer.
|
||||||
|
* @param src The source string.
|
||||||
|
* @param size The size of the destination buffer.
|
||||||
|
* @return The length of the (non-truncated) result, i.e. strlen(src).
|
||||||
|
*/
|
||||||
|
size_t strlcpy(char *dst, const char *src, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the string src to the string dst. Note that both src and dst must be
|
||||||
|
* zero terminated. The result will be zero terminated. At most
|
||||||
|
* "size - strlen(dst) - 1" bytes will be appended.
|
||||||
|
*
|
||||||
|
* In case the dst string does not contain a zero within the first "size" bytes
|
||||||
|
* the dst string will not be changed and size + strlen(src) is returned.
|
||||||
|
*
|
||||||
|
* @note This is modeled after OpenBSD's strlcat. See the manpage here:
|
||||||
|
* http://www.openbsd.org/cgi-bin/man.cgi?query=strlcat
|
||||||
|
*
|
||||||
|
* @param dst The string the source string should be appended to.
|
||||||
|
* @param src The source string.
|
||||||
|
* @param size The (total) size of the destination buffer.
|
||||||
|
* @return The length of the (non-truncated) result. That is
|
||||||
|
* strlen(dst) + strlen(src). In case strlen(dst) > size
|
||||||
|
* size + strlen(src) is returned.
|
||||||
|
*/
|
||||||
|
size_t strlcat(char *dst, const char *src, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience wrapper for tag2string which "returns" a C string.
|
* Convenience wrapper for tag2string which "returns" a C string.
|
||||||
* Note: It is *NOT* safe to do anything with the return value other than directly
|
* Note: It is *NOT* safe to do anything with the return value other than directly
|
||||||
|
|
|
@ -295,6 +295,58 @@ class StringTestSuite : public CxxTest::TestSuite
|
||||||
Common::String s = Common::String::printf("%s%X", "test", 1234);
|
Common::String s = Common::String::printf("%s%X", "test", 1234);
|
||||||
TS_ASSERT(s == "test4D2");
|
TS_ASSERT(s == "test4D2");
|
||||||
TS_ASSERT(s.size() == 7);
|
TS_ASSERT(s.size() == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_strlcpy() {
|
||||||
|
static const char * const testString = "1234567890";
|
||||||
|
|
||||||
|
char test1[4];
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test1, testString, 4), strlen(testString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test1, "123"), 0);
|
||||||
|
|
||||||
|
char test2[12];
|
||||||
|
test2[11] = 'X';
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test2, testString, 11), strlen(testString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test2, testString), 0);
|
||||||
|
TS_ASSERT_EQUALS(test2[11], 'X');
|
||||||
|
|
||||||
|
char test3[1] = { 'X' };
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test3, testString, 0), strlen(testString));
|
||||||
|
TS_ASSERT_EQUALS(test3[0], 'X');
|
||||||
|
|
||||||
|
char test4[12];
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test4, testString, 12), strlen(testString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test4, testString), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_strncat() {
|
||||||
|
static const char * const initialString = "123";
|
||||||
|
static const char * const appendString = "4567890";
|
||||||
|
static const char * const resultString = "1234567890";
|
||||||
|
|
||||||
|
char test1[4];
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test1, initialString, 4), strlen(initialString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test1, initialString), 0);
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcat(test1, appendString, 4), strlen(resultString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test1, initialString), 0);
|
||||||
|
|
||||||
|
char test2[12];
|
||||||
|
test2[11] = 'X';
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test2, initialString, 11), strlen(initialString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test2, initialString), 0);
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcat(test2, appendString, 11), strlen(resultString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test2, resultString), 0);
|
||||||
|
TS_ASSERT_EQUALS(test2[11], 'X');
|
||||||
|
|
||||||
|
char test3[1];
|
||||||
|
test3[0] = 'X';
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcat(test3, appendString, 0), strlen(appendString));
|
||||||
|
TS_ASSERT_EQUALS(test3[0], 'X');
|
||||||
|
|
||||||
|
char test4[11];
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcpy(test4, initialString, 11), strlen(initialString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test4, initialString), 0);
|
||||||
|
TS_ASSERT_EQUALS(Common::strlcat(test4, appendString, 11), strlen(resultString));
|
||||||
|
TS_ASSERT_EQUALS(strcmp(test4, resultString), 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue