summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkarl <karl>2014-06-14 16:14:04 +0000
committerkarl <karl>2014-06-14 16:14:04 +0000
commit0545e3979ae49808d0bd34e49f6ab83014926cbb (patch)
tree60e96e89f0f96ba09576454e228c2433f4b1bd22
parent4d23c9a59165105b909eecba57f8a482e11deacf (diff)
downloadtog-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.cpp92
-rw-r--r--src/Pegasus/Common/String.h18
-rw-r--r--src/Pegasus/Common/tests/String/String.cpp153
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);
}