summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkarl <karl>2005-02-06 22:22:03 +0000
committerkarl <karl>2005-02-06 22:22:03 +0000
commitf861e0f70c86ed5d4fffde5b2aba4ced9e7f6ed7 (patch)
treef91555487d153aff53c1f91b4790b7e0d2da1177
parent710b03f5261a7c92f503f3a95d7424eed8dc9972 (diff)
downloadtog-pegasus-PEP217_BRANCH.zip
tog-pegasus-PEP217_BRANCH.tar.gz
tog-pegasus-PEP217_BRANCH.tar.xz
PEP#: 217PEP217_BRANCH
TITLE: Initial string formatting code. DESCRIPTION: Initial string formatting routines for PEP217
-rw-r--r--src/Pegasus/Common/StrFormat.cpp475
-rw-r--r--src/Pegasus/Common/StrFormat.h137
2 files changed, 612 insertions, 0 deletions
diff --git a/src/Pegasus/Common/StrFormat.cpp b/src/Pegasus/Common/StrFormat.cpp
new file mode 100644
index 0000000..b544e2e
--- /dev/null
+++ b/src/Pegasus/Common/StrFormat.cpp
@@ -0,0 +1,475 @@
+//%2004////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
+// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
+// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
+// IBM Corp.; EMC Corporation, The Open Group.
+// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
+// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
+// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
+// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//==============================================================================
+//
+// Author: Michael E. Brasher
+//
+//%/////////////////////////////////////////////////////////////////////////////
+
+#include <cstring>
+#include <cctype>
+#include <cstdarg>
+#include <cassert>
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Common/String.h>
+#include <Pegasus/Common/CIMDateTime.h>
+#include "StrFormat.h"
+
+#define MAX_ARGS 100
+
+PEGASUS_NAMESPACE_BEGIN
+
+struct Spec
+{
+ char used;
+ char tag;
+
+ union
+ {
+ Boolean arg_o;
+ Sint8 arg_b;
+ Sint8 arg_B;
+ Sint16 arg_s;
+ Sint16 arg_S;
+ Sint32 arg_i;
+ Sint32 arg_I;
+ Sint64 arg_l;
+ Sint64 arg_L;
+ Real32 arg_f;
+ Real64 arg_d;
+ char arg_c;
+ Char16* arg_C;
+ char* arg_z;
+ String* arg_Z;
+ CIMDateTime* arg_t;
+ };
+};
+
+static void _PrintSpec(
+ char*& str,
+ size_t& str_size,
+ size_t& str_cap,
+ const Spec& spec)
+{
+ /* Make room for 64 bytes up front */
+
+ if (str_size + 64 >= str_cap)
+ {
+ str_cap += 64;
+ str = (char*)realloc(str, str_cap);
+ }
+
+ /* Insert new argument */
+
+ switch(spec.tag)
+ {
+ case 'o':
+ {
+ if (spec.arg_o)
+ {
+ strcat(str, "true");
+ str_size += 4;
+ }
+ else
+ {
+ strcat(str, "false");
+ str_size += 5;
+ }
+ break;
+ }
+ case 'b':
+ {
+ size_t n = sprintf(str + str_size, "%d", spec.arg_b);
+ str_size += n;
+ break;
+ }
+ case 'B':
+ {
+ size_t n = sprintf(str + str_size, "%u", spec.arg_B);
+ str_size += n;
+ break;
+ }
+ case 's':
+ {
+ size_t n = sprintf(str + str_size, "%d", spec.arg_s);
+ str_size += n;
+ break;
+ }
+ case 'S':
+ {
+ size_t n = sprintf(str + str_size, "%u", spec.arg_S);
+ str_size += n;
+ break;
+ }
+ case 'i':
+ {
+ size_t n = sprintf(str + str_size, "%d", spec.arg_i);
+ str_size += n;
+ break;
+ }
+ case 'I':
+ {
+ size_t n = sprintf(str + str_size, "%u", spec.arg_I);
+ str_size += n;
+ break;
+ }
+ case 'l':
+ {
+ size_t n = sprintf(str + str_size,
+ "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", spec.arg_l);
+ str_size += n;
+ break;
+ }
+ case 'L':
+ {
+ size_t n = sprintf(str + str_size,
+ "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", spec.arg_L);
+ str_size += n;
+ break;
+ }
+ case 'f':
+ {
+ size_t n = sprintf(str + str_size, "%f", spec.arg_f);
+ str_size += n;
+ break;
+ }
+ case 'd':
+ {
+ size_t n = sprintf(str + str_size, "%lf", spec.arg_d);
+ str_size += n;
+ break;
+ }
+ case 'c':
+ {
+ size_t n = sprintf(str + str_size, "%c", spec.arg_c);
+ str_size += n;
+ break;
+ }
+ case 'C':
+ {
+ size_t n = sprintf(str + str_size, "%04X", (Uint16)(*spec.arg_C));
+ str_size += n;
+ break;
+ }
+ case 'z':
+ {
+ size_t len = strlen(spec.arg_z);
+
+ if (str_size + len >= str_cap)
+ {
+ str_cap += len;
+ str = (char*)realloc(str, str_cap);
+ }
+ strcat(str + str_size, spec.arg_z);
+ str_size += len;
+ break;
+ }
+ case 'Z':
+ {
+ CString cstring = spec.arg_Z->getCString();
+ const char* c_str = cstring;
+ size_t len = strlen(c_str);
+
+ if (str_size + len >= str_cap)
+ {
+ str_cap += len;
+ str = (char*)realloc(str, str_cap);
+ }
+ strcat(str + str_size, c_str);
+ str_size += len;
+ break;
+ }
+ case 't':
+ {
+ // ATTN: implement this!
+ assert("NOT IMPLEMENTED!" == 0);
+ break;
+ }
+ default:
+ /* Not reachable */
+ break;
+ }
+}
+
+static char _valid_tags[] = "obBsSiIlLfFcCzZd";
+
+int VaStrFormat(char*& str, const char* format, va_list ap)
+{
+ Spec specs[MAX_ARGS];
+ size_t specs_size = 0;
+
+ /*
+ * Clear out specs array
+ */
+
+ memset(specs, 0, sizeof specs);
+
+ /*
+ * Make string null for now in case an error occurs.
+ */
+
+ str = NULL;
+
+ /*
+ * Scan the format and find the highest valued argument number.
+ */
+
+ for (const char* p = format; *p; )
+ {
+ if (*p == '%')
+ {
+ p++;
+
+ if (isdigit(*p))
+ {
+ /* Convert the argument number to integer */
+
+ const char* start = p;
+ char* end;
+ unsigned long arg_num = strtoul(start, &end, 10);
+ p = end;
+
+ if (arg_num >= MAX_ARGS)
+ return -1;
+
+ /* Get the tag character */
+
+ char tag = *p++;
+
+ if (strchr(_valid_tags, tag) == NULL)
+ {
+ /* Invalid tag character */
+ return -1;
+ }
+
+ /* Create a spec entry */
+
+ specs[arg_num].tag = tag;
+ specs[arg_num].used = 1;
+
+ if (specs_size <= arg_num)
+ specs_size = arg_num + 1;
+ }
+ else if (*p == '%')
+ {
+ /* double percent */
+ p++;
+ continue;
+ }
+ else
+ return -1;
+ }
+ else
+ p++;
+ }
+
+ /*
+ * Check for gaps in the specs (an error)
+ */
+
+ for (size_t i = 0; i < specs_size; i++)
+ {
+ if (!specs[i].used)
+ return -1;
+ }
+
+ /*
+ * Iterate over the specs, getting all the arguments.
+ */
+
+ for (size_t i = 0; i < specs_size; i++)
+ {
+ switch(specs[i].tag)
+ {
+ case 'o':
+ {
+ specs[i].arg_o = va_arg(ap, int);
+ break;
+ }
+ case 'b':
+ {
+ specs[i].arg_b = va_arg(ap, int);
+ break;
+ }
+ case 'B':
+ {
+ specs[i].arg_B = va_arg(ap, int);
+ break;
+ }
+ case 's':
+ {
+ specs[i].arg_s = va_arg(ap, int);
+ break;
+ }
+ case 'S':
+ {
+ specs[i].arg_S = va_arg(ap, int);
+ break;
+ }
+ case 'i':
+ {
+ specs[i].arg_i = va_arg(ap, Sint32);
+ break;
+ }
+ case 'I':
+ {
+ specs[i].arg_I = va_arg(ap, Uint32);
+ break;
+ }
+ case 'l':
+ {
+ specs[i].arg_l = va_arg(ap, Sint64);
+ break;
+ }
+ case 'L':
+ {
+ specs[i].arg_L = va_arg(ap, Uint64);
+ break;
+ }
+ case 'f':
+ {
+ specs[i].arg_f = va_arg(ap, double);
+ break;
+ }
+ case 'd':
+ {
+ specs[i].arg_d = va_arg(ap, double);
+ break;
+ }
+ case 'c':
+ {
+ specs[i].arg_c = va_arg(ap, int);
+ break;
+ }
+ case 'C':
+ {
+ specs[i].arg_C = va_arg(ap, Char16*);
+ break;
+ }
+ case 'z':
+ {
+ specs[i].arg_z = va_arg(ap, char*);
+ break;
+ }
+ case 'Z':
+ {
+ specs[i].arg_Z = va_arg(ap, String*);
+ break;
+ }
+ case 't':
+ {
+ specs[i].arg_t = va_arg(ap, CIMDateTime*);
+ break;
+ }
+ default:
+ return -1;
+ }
+ }
+
+ va_end(ap);
+
+ /*
+ * At last! Build the string.
+ */
+
+ /*
+ * Guess at the required size (extened allocation later if necessary).
+ */
+
+ const size_t GROW_BY = 64;
+ size_t str_cap = 64;
+ size_t str_size = 0;
+
+ if ((str = (char*)malloc(str_cap)) == NULL)
+ return -1;
+
+ *str = '\0';
+
+ /*
+ * Scan the format and find the highest valued argument number.
+ */
+
+ for (const char* p = format; *p; )
+ {
+ if (*p == '%')
+ {
+ p++;
+
+ if (isdigit(*p))
+ {
+ /* Get argument number */
+
+ const char* start = p;
+ char* end;
+ unsigned long arg_num = strtoul(start, &end, 10);
+ p = end;
+
+ /* Skip over tag */
+
+ p++;
+
+ _PrintSpec(str, str_size, str_cap, specs[arg_num]);
+ }
+ else if (*p == '%')
+ {
+ if (str_size + 1 >= str_cap)
+ {
+ str_cap += GROW_BY;
+ str = (char*)realloc(str, str_cap);
+ }
+ str[str_size++] = '%';
+ str[str_size] = '\0';
+ p++;
+ }
+ else
+ {
+ /* Not reachable (checked earlier). */
+ return -1;
+ }
+ }
+ else
+ {
+ if (str_size + 1 >= str_cap)
+ {
+ str_cap += GROW_BY;
+ str = (char*)realloc(str, str_cap);
+ }
+ str[str_size++] = *p++;
+ str[str_size] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+int StrFormat(char*& str, const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ return VaStrFormat(str, format, ap);
+}
+
+PEGASUS_NAMESPACE_END
diff --git a/src/Pegasus/Common/StrFormat.h b/src/Pegasus/Common/StrFormat.h
new file mode 100644
index 0000000..8454f37
--- /dev/null
+++ b/src/Pegasus/Common/StrFormat.h
@@ -0,0 +1,137 @@
+//%2004////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
+// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
+// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
+// IBM Corp.; EMC Corporation, The Open Group.
+// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
+// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
+// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
+// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//==============================================================================
+//
+// Author: Michael E. Brasher
+//
+//%/////////////////////////////////////////////////////////////////////////////
+
+#ifndef Pegasus_Format_h
+#define Pegasus_Format_h
+
+#include <Pegasus/Common/Config.h>
+
+PEGASUS_NAMESPACE_BEGIN
+
+/** Builds a string from a variable list of arguments. The format string
+ specifies how the subsequent arguments are transformed into a string.
+ The format string is scanned from left to right and copied to the output
+ string until a '%' character is encountered. The '%' character introduces
+ a 'specifier' which indicates how one of subsequent arguments is
+ transformed and copied to the output string. The specifier has the
+ following form.
+
+ <pre>
+ "%" argument tag
+ </pre>
+
+ That is, a percent character followed a zero-based argument number
+ (indicating which argument to transform) and then by a character
+ tag indicating the type of the argument. For example.
+
+ <pre>
+ %0z -- transform the first argument of type char* (given by 'z')
+ %3i -- transform the fourth argument of type Sint32 (given by 'i')
+ %5L -- transform the sixth argument of type uint64 (given by 'L')
+ </pre>
+
+ Like printf(), '%%' is used to specify a percent character.
+
+ Here are the valid tags and their corresponding types.
+
+ <pre>
+ o -- boolean (mnemonic: b[o]olean)
+ b -- sint8 (mnemonic: [b]yte)
+ B -- uint8 (mnemonic: [B]yte)
+ s -- sint16 (mnemonic: [s]hort)
+ S -- uint16 (mnemonic: [S]hort)
+ i -- sint32 (mnemonic: [i]nt)
+ I -- uint32 (mnemonic: [I]nt)
+ l -- sint64 (mnemonic: [l]ong)
+ L -- uint64 (mnemonic: [L]ong)
+ f -- real32 (mnemonic: [f]loat)
+ d -- real64 (mnemonic: [d]ouble)
+ c -- char (mnemonic: [c]har)
+ C -- char16 (mnemonic: [C]har)
+ z -- char* (mnemonic: [z]tring)
+ Z -- String (mnemonic: [Z]tring)
+ t -- datetime (menmonic: date[t]ime)
+ </pre>
+
+ Consider the following example, which prints the date and day of the week.
+
+ <pre>
+ Uint32 month;
+ Uint32 day;
+ Uint32 year;
+ String day_of_week;
+
+ char* str;
+
+ StrFormat(str,
+ "Month: %0I/%1I/%2I %3Z\n", month, day, year, &day_of_week);
+ </pre>
+
+ The argument numbers are essential for performing localization. For
+ example, to put the date in European format, the specifiers may be
+ reordered. This works well since format string are typically obtained
+ from an language localization file. For example:
+
+ <pre>
+ StrFormat(str,
+ "Month: %2I/%0I/%1I %3Z\n", month, day, year, &day_of_week);
+ </pre>
+
+ The scheme above has five major advantages over the printf() family of
+ routines in the standard library. First, the CIM types are expressly
+ supported without ambiguity. For example, the size of integers and longs
+ may vary across platforms but StrFormat() specifiers are defined in terms
+ of the actual size of the integer types. Second, StrFormat() supports
+ printing of sixty-four bit integers. Third, it is possible to print String
+ objects without converting them to 'char*' up front. Fourth, StrFormat()
+ supports printing to a string (whereas, the standard library provides
+ no standard mechanism). And finally, arguments may be reordered by the
+ format statement.
+
+ Note that it is an error to use an argument more than once. It is also
+ an error to skip over arguments (for every argument, there must be a
+ corresponing specifier).
+
+ @param str points to a newly allocated string upon return. The caller
+ is responsible for passing the string to free().
+ @param format format string as described above.
+ @return the number of characters copied to the str argument.
+*/
+int StrFormat(char*& str, const char* format, ...);
+
+/** Similar to StrFormat() but accepts a va_list rather than a variable
+ argument list.
+*/
+int VaStrFormat(char*& str, const char* format, va_list ap);
+
+PEGASUS_NAMESPACE_END
+
+#endif /* Pegasus_Format_h */