diff options
author | karl <karl> | 2014-06-14 16:14:04 +0000 |
---|---|---|
committer | karl <karl> | 2014-06-14 16:14:04 +0000 |
commit | 0545e3979ae49808d0bd34e49f6ab83014926cbb (patch) | |
tree | 60e96e89f0f96ba09576454e228c2433f4b1bd22 | |
parent | 4d23c9a59165105b909eecba57f8a482e11deacf (diff) | |
download | tog-pegasus-0545e3979ae49808d0bd34e49f6ab83014926cbb.zip tog-pegasus-0545e3979ae49808d0bd34e49f6ab83014926cbb.tar.gz tog-pegasus-0545e3979ae49808d0bd34e49f6ab83014926cbb.tar.xz |
BUG#: 9880
TITLE: Extend String class with a method to append using printf format
DESCRIPTION: add appendPrintf method to String.h and String.cpp that
appends data to a Pegasus String using the printf formatting mechanism
to build the data to append.
-rw-r--r-- | src/Pegasus/Common/String.cpp | 92 | ||||
-rw-r--r-- | src/Pegasus/Common/String.h | 18 | ||||
-rw-r--r-- | src/Pegasus/Common/tests/String/String.cpp | 153 |
3 files changed, 257 insertions, 6 deletions
diff --git a/src/Pegasus/Common/String.cpp b/src/Pegasus/Common/String.cpp index 2b60cee..fab674f 100644 --- a/src/Pegasus/Common/String.cpp +++ b/src/Pegasus/Common/String.cpp @@ -34,6 +34,8 @@ #include "InternalException.h" #include "MessageLoader.h" #include "StringRep.h" +#include <Pegasus/Common/Pegasus_inl.h> +#include <cstdarg> #ifdef PEGASUS_HAS_ICU # include <unicode/ures.h> @@ -380,6 +382,49 @@ static inline size_t _copyToUTF8(char* dest, const Uint16* src, size_t n) return p - (Uint8*)dest; } +// Function to return a formatted char* from a va_list. +// Allocates space for the returned char* and repeats the +// build process until the allocated space is large enough +// to hold the result. This is internal only and the core function +// used by stringPrintf and stringVPrintf + +static char* _charVPrintf(const char* format, va_list ap) +{ + // Iniitial allocation size. This is a guess assuming that + // most printfs are one or two lines long + int allocSize = 256; + + int rtnSize; + char *p; + + // initial allocate for output + if ((p = (char*)malloc(allocSize)) == NULL) + { + return 0; + } + + // repeat formatting with increased realloc until it works. + do + { + rtnSize = vsnprintf(p, allocSize, format, ap); + + // return if successful if not negative and + // returns less than allocated size. + if (rtnSize > -1 && rtnSize < allocSize) + { + return p; + } + + // increment alloc size. Assumes that positive return is + // expected size and negative is error. + allocSize = (rtnSize > -1)? (rtnSize + 1) : allocSize * 2; + + } while((p = (char*)peg_inln_realloc(p, allocSize)) != NULL); + + // return error code if realloc failed + return 0; +} + //============================================================================== // // class CString @@ -1141,6 +1186,53 @@ Boolean String::equal(const String& s1, const String& s2) s1._rep->size * sizeof(Uint16)) == 0); } +void String::appendPrintf(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + + // Format into allocated memory + ////char* rtnCharPtr = _charVPrintf(format, ap); + + // Iniitial allocation size. This is a guess assuming that + // most printfs are one or two lines long + int allocSize = 256; + int rtnSize; + char *p; + + // initial allocate for output + if ((p = (char*)malloc(allocSize)) == NULL) + { + return; + } + + // repeat formatting with increased realloc until it works. + do + { + rtnSize = vsnprintf(p, allocSize, format, ap); + + // return if successful; i.e. if not negative and + // returns less than allocated size. + if (rtnSize > -1 && rtnSize < allocSize) + { + break; + } + + // increment alloc size. Positive return is + // expected size and negative is error. + allocSize = (rtnSize > -1)? (rtnSize + 1) : allocSize * 2; + + } while((p = (char*)peg_inln_realloc(p, allocSize)) != NULL); + + // get here only with error in malloc. + + va_end(ap); + + // Free allocated memory append printf output to current string + append(p, rtnSize); + free(p); +} + Boolean String::equal(const String& s1, const char* s2) { #ifdef PEGASUS_STRING_NO_UTF8 diff --git a/src/Pegasus/Common/String.h b/src/Pegasus/Common/String.h index b36ecf3..9890b6e 100644 --- a/src/Pegasus/Common/String.h +++ b/src/Pegasus/Common/String.h @@ -44,6 +44,7 @@ #include <Pegasus/Common/Config.h> #include <Pegasus/Common/Char16.h> #include <Pegasus/Common/Linkage.h> +#include <cstdarg> PEGASUS_NAMESPACE_BEGIN @@ -444,6 +445,18 @@ public: */ void toLower(); + /** + Constructs a String based on printf specifications. For some + compilers the PEGASUS_FORMAT generates warning messages if + the format string does not match the input arguments. + @param format const char * The format specification as defined + for printf. The format specification corresponds to the + standard C++ printf format specification + @param ... The list of arguments that will be formated. + */ + PEGASUS_FORMAT(2,3) + void appendPrintf(const char* format, ...); + #ifdef PEGASUS_USE_EXPERIMENTAL_INTERFACES /** <I><B>Experimental Interface</B></I><BR> @@ -499,10 +512,7 @@ public: /** Compares two strings and returns true if they are equal independent of the case of the characters. - @param s1 The first String to compare. - @param s2 The second String to compare. - @return true if the strings are equal independent of case, false - otherwise. + @param ... Variable arguments as defined for printf */ static Boolean equalNoCase(const String& s1, const String& s2); diff --git a/src/Pegasus/Common/tests/String/String.cpp b/src/Pegasus/Common/tests/String/String.cpp index 20fb44f..85ff334 100644 --- a/src/Pegasus/Common/tests/String/String.cpp +++ b/src/Pegasus/Common/tests/String/String.cpp @@ -40,6 +40,8 @@ PEGASUS_USING_PEGASUS; PEGASUS_USING_STD; +#define VCOUT if (verbose) cout + static Boolean verbose; int test(char** argv) @@ -1441,15 +1443,162 @@ int test(char** argv) } PEGASUS_TEST_ASSERT(caughtBadAlloc); - cout << argv[0] << " +++++ passed all tests" << endl; - char* p = (char*)operator new(88888); operator delete(p); + // Test appendPrintf + + // Test the various basic C++ basic integer and string types + { + String prtf; + prtf.appendPrintf("%u", 1234); + PEGASUS_TEST_ASSERT(prtf == "1234"); + } + + { + String prtf; + const char* teststr = "1234"; + prtf.appendPrintf("%s", teststr); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == teststr); + } + + { + String prtf; + const char* teststr = "123456789abcdefghighklmnopqrstuvwxyz!@#$%^&*()"; + prtf.appendPrintf("%s", teststr); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == teststr); + } + + { + String prtf; + unsigned int usi = 948; + prtf.appendPrintf("%u", usi); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "948"); + } + { + String prtf; + unsigned int si = -948; + prtf.appendPrintf("%d", si); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "-948"); + } + { + String prtf; + unsigned long int uli= 888888; + prtf.appendPrintf("%lu", uli); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "888888"); + + } + + // test against the Pegasus types cast + { + String prtf; + Uint64 u64 = 99999; + prtf.appendPrintf("%lu", (unsigned long int) u64); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "99999"); + } + + { + String prtf; + Uint32 u32 = 32512; + prtf.appendPrintf("%u", (unsigned int)u32); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "32512"); + } + + { + String prtf; + Uint32 u32 = 32; + Uint64 u64 = 99999; + Sint32 s32 = -12; + signed long int sli = 12345678; + char str1[] = "abcd"; + String str2 = "cdef"; + const char* str3 = "defg"; + prtf.appendPrintf(" Test %u %lu %d %ld %s%s%s%s ", (unsigned int)u32, + (unsigned long)u64, (int)s32, sli, + str1, (const char *)str2.getCString(), str3, "hijk"); + + String result = " Test 32 99999 -12 12345678 abcdcdefdefghijk "; + VCOUT << "prtf " << prtf << "\nresult " << result << endl; + PEGASUS_TEST_ASSERT(prtf == result); + } + { + String prtf = "abcd"; + prtf.appendPrintf("%s", "efgh"); + prtf.appendPrintf("%s", "ijkl"); + String result = "abcdefghijkl"; + PEGASUS_TEST_ASSERT(prtf == result); + } +// The following are not normally compiled. They test that compile +// errors are generated on at least the supported compilers when +// there are differences between the format string and the input arguments +// Today this is only the gcc compiler + +// Enable following define to test compile warning generation. +//#define COMPILER_ERROR_TESTS +#ifdef COMPILER_ERROR_TESTS + // Test of compiler generating errors in printf specification + { + String prtf; + prtf.appendPrintf("%u incompatible type", "1234"); + VCOUT << __LINE__ << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "1234"); + } + { + String prtf; + prtf.appendPrintf("%s incompatible type", 1234); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "1234"); + } + { + String prtf; + Uint64 u64 = 99999; + prtf.appendPrintf("%lu no cast", u64); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "99999"); + } + { + String prtf; + Uint32 u32 = 32512; + prtf.appendPrintf("%lu incompatible type", (unsigned int)u32); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "32512"); + } + { + String prtf; + Uint32 u32 = 32512; + prtf.appendPrintf("No format cmds", (unsigned int)u32); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "32512"); + } + { + String prtf; + Uint32 u32 = 32512; + prtf.appendPrintf("%u using Uint32", u32); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "32512"); + } + { + String prtf; + Uint32 u32 = 32512; + prtf.appendPrintf("%u extra arg",(unsigned int)u32, "arg 2"); + VCOUT << __LINE__ << " " << prtf << endl; + PEGASUS_TEST_ASSERT(prtf == "32512"); + } +#endif + cout << argv[0] << " +++++ passed all tests" << endl; + return 0; } int main(int, char** argv) { + verbose = (getenv("PEGASUS_TEST_VERBOSE")) ? true : false; return test(argv); } |