summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Huston <shuston@riverace.com>2001-07-27 02:15:26 +0000
committerSteve Huston <shuston@riverace.com>2001-07-27 02:15:26 +0000
commit37dc12af3efcd6ebd5266b7f2e21b01ae4d7cfda (patch)
tree7489803f45380af4a66e19a4bbe7a861af5d77db
parentb4abf8fd541fe27190d74db4ce86e4738f46440e (diff)
downloadATCD-37dc12af3efcd6ebd5266b7f2e21b01ae4d7cfda.tar.gz
ChangeLogTag:Thu Jul 26 22:09:19 2001 Steve Huston <shuston@riverace.com>
-rw-r--r--ChangeLog14
-rw-r--r--ChangeLogs/ChangeLog-02a14
-rw-r--r--ChangeLogs/ChangeLog-03a14
-rw-r--r--ace/Log_Msg.cpp412
-rw-r--r--tests/Log_Msg_Test.cpp115
5 files changed, 385 insertions, 184 deletions
diff --git a/ChangeLog b/ChangeLog
index fe2df491201..e6ea2415a2a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Thu Jul 26 22:09:19 2001 Steve Huston <shuston@riverace.com>
+
+ * ace/Log_Msg.cpp (log): Extend behavior so that all printf
+ formatting conversion specifiers can be used with all legal
+ ACE_Log_Msg format characters. This allows the caller to line
+ up columns on any field, like line number or program name, or
+ thread ID. Thanks to Paul Caffrey <pcaffrey@iel.ie> for
+ motivating this extension.
+
+ * tests/Log_Msg_Test.cpp: Added a new function, test_format_specs,
+ that verifies the formatting. Right now it does not detect the
+ correctness of the strings produced - they have to be examined
+ in the log file to check. This needs to be fixed still.
+
Thu Jul 26 11:48:16 2001 Carlos O'Ryan <coryan@uci.edu>
* bin/count_lines:
diff --git a/ChangeLogs/ChangeLog-02a b/ChangeLogs/ChangeLog-02a
index fe2df491201..e6ea2415a2a 100644
--- a/ChangeLogs/ChangeLog-02a
+++ b/ChangeLogs/ChangeLog-02a
@@ -1,3 +1,17 @@
+Thu Jul 26 22:09:19 2001 Steve Huston <shuston@riverace.com>
+
+ * ace/Log_Msg.cpp (log): Extend behavior so that all printf
+ formatting conversion specifiers can be used with all legal
+ ACE_Log_Msg format characters. This allows the caller to line
+ up columns on any field, like line number or program name, or
+ thread ID. Thanks to Paul Caffrey <pcaffrey@iel.ie> for
+ motivating this extension.
+
+ * tests/Log_Msg_Test.cpp: Added a new function, test_format_specs,
+ that verifies the formatting. Right now it does not detect the
+ correctness of the strings produced - they have to be examined
+ in the log file to check. This needs to be fixed still.
+
Thu Jul 26 11:48:16 2001 Carlos O'Ryan <coryan@uci.edu>
* bin/count_lines:
diff --git a/ChangeLogs/ChangeLog-03a b/ChangeLogs/ChangeLog-03a
index fe2df491201..e6ea2415a2a 100644
--- a/ChangeLogs/ChangeLog-03a
+++ b/ChangeLogs/ChangeLog-03a
@@ -1,3 +1,17 @@
+Thu Jul 26 22:09:19 2001 Steve Huston <shuston@riverace.com>
+
+ * ace/Log_Msg.cpp (log): Extend behavior so that all printf
+ formatting conversion specifiers can be used with all legal
+ ACE_Log_Msg format characters. This allows the caller to line
+ up columns on any field, like line number or program name, or
+ thread ID. Thanks to Paul Caffrey <pcaffrey@iel.ie> for
+ motivating this extension.
+
+ * tests/Log_Msg_Test.cpp: Added a new function, test_format_specs,
+ that verifies the formatting. Right now it does not detect the
+ correctness of the strings produced - they have to be examined
+ in the log file to check. This needs to be fixed still.
+
Thu Jul 26 11:48:16 2001 Carlos O'Ryan <coryan@uci.edu>
* bin/count_lines:
diff --git a/ace/Log_Msg.cpp b/ace/Log_Msg.cpp
index 7ab6440262f..52c88af6e2a 100644
--- a/ace/Log_Msg.cpp
+++ b/ace/Log_Msg.cpp
@@ -851,12 +851,6 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
ACE_TCHAR *bp = ACE_const_cast (ACE_TCHAR *, this->msg ());
int abort_prog = 0;
int exit_value = 0;
- ACE_TCHAR *format;
- ACE_ALLOCATOR_RETURN (format, ACE_OS::strdup (format_str), -1);
- ACE_TCHAR *save_p = format; // Remember pointer for ACE_OS::free()
-
- if (format == 0)
- return -1;
if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::VERBOSE))
{
@@ -873,93 +867,148 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
}
}
- while (*format != '\0')
+ while (*format_str != '\0')
{
// Copy input to output until we encounter a %, however a
// % followed by another % is not a format specification.
- if (*format != '%')
- *bp++ = *format++;
- else if (format[1] == '%') // An "escaped" '%' (just print one '%').
+ if (*format_str != '%')
+ *bp++ = *format_str++;
+ else if (format_str[1] == '%') // An "escaped" '%' (just print one '%').
{
- *bp++ = *format++; // Store first %
- format++; // but skip second %
+ *bp++ = *format_str++; // Store first %
+ format_str++; // but skip second %
}
else
{
- ACE_TCHAR c = '\0'; // high use character
- ACE_TCHAR *fp; // local format pointer
- int wpc; // width/precision cnt
- const int CONTINUE = 0;
- const int SKIP_SPRINTF = -1; // We must skip the sprintf phase
- const int SKIP_NUL_LOCATE = -2; // Skip locating the NUL character
- int type = CONTINUE; // conversion type
- int w[2]; // width/precision vals
-
- // % starts a format specification that ends with one of
- // "arnPpSsdciIouxXfFeEgG". An optional width and/or precision
- // (indicated by an "*") may be encountered prior to the
- // nend of the specification, each consumes an int arg.
- // A call to sprintf() does the actual conversion.
-
- fp = format++; // Remember beginning of format.
- wpc = 0; // Assume no width/precision seen.
-
- while (type == CONTINUE)
+ // This is most likely a format specification that ends with
+ // one of the valid options described previously. To enable full
+ // use of all sprintf capabilities, save the format specifier
+ // from the '%' up to the format letter in a new char array.
+ // This allows the full sprintf capability for padding, field
+ // widths, alignment, etc. Any width/precision requiring a
+ // caller-supplied argument is extracted and placed as text
+ // into the format array. Lastly, we convert the caller-supplied
+ // format specifier from the ACE_Log_Msg-supported list to the
+ // equivalent sprintf specifier, and run the new format spec
+ // through sprintf, adding it to the bp string.
+
+ const ACE_TCHAR *start_format = format_str;
+ ACE_TCHAR format[128]; // Converted format string
+ ACE_TCHAR *fp; // Current format pointer
+ int wp = 0; // Width/precision extracted from args
+ int done = 0;
+ int skip_nul_locate = 0;
+
+ fp = format;
+ *fp++ = *format_str++; // Copy in the %
+
+ // Work through the format string to copy in the format
+ // from the caller. While it's going across, extract ints
+ // for '*' width/precision values from the argument list.
+ // When the real format specifier is located, change it to
+ // one recognized by sprintf, if needed, and do the sprintf
+ // call.
+
+ while (!done)
{
- switch (*format++)
+ done = 1; // Unless a conversion spec changes it
+
+ switch (*format_str)
{
- case 'A':
- type = SKIP_SPRINTF;
+ // The initial set of cases are the conversion
+ // specifiers. Copy them in to the format array.
+ // Note we don't use 'l', a normal conversion spec,
+ // as a conversion because it is a ACE_Log_Msg format
+ // specifier.
+ case '-':
+ case '+':
+ case '0':
+ case ' ':
+ case '#':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ case 'L':
+ case 'h':
+ *fp++ = *format_str;
+ done = 0;
+ break;
+
+ case '*':
+ wp = va_arg (argp, int);
+ ACE_OS::sprintf (fp, ACE_LIB_TEXT ("%d"), wp);
+ fp += ACE_OS::strlen (fp);
+ done = 0;
+ break;
+
+ case 'A': // ACE_timer_t
{
#if defined (ACE_LACKS_FLOATING_POINT)
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("ld"));
ACE_UINT32 value = va_arg (argp, ACE_UINT32);
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%ld"), value);
+ ACE_OS::sprintf (bp, format, value);
#else
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("f"));
double value = va_arg (argp, double);
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%f"), value);
+ ACE_OS::sprintf (bp, format, value);
#endif /* ACE_LACKS_FLOATING_POINT */
}
break;
+
case 'a': // Abort program after handling all of format string.
- type = SKIP_SPRINTF;
abort_prog = 1;
exit_value = va_arg (argp, int);
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("Aborting..."));
+ ACE_OS::strcpy (bp, ACE_LIB_TEXT ("Aborting..."));
// Make sure to NULL terminate this...
break;
- case 'l':
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%d"), this->linenum ());
- type = SKIP_SPRINTF;
+
+ case 'l': // Source file line number
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("d"));
+ ACE_OS::sprintf (bp, format, this->linenum ());
break;
- case 'N':
- // @@ UNICODE
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%s"),
+
+ case 'N': // Source file name
+ // @@ UNICODE
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp, format,
this->file () ?
ACE_TEXT_CHAR_TO_TCHAR (this->file ())
: ACE_LIB_TEXT ("<unknown file>"));
- type = SKIP_SPRINTF;
break;
- case 'n': // Print the name of the program.
- type = SKIP_SPRINTF;
+
+ case 'n': // Program name
// @@ UNICODE
- ACE_OS::strcpy (bp, ACE_Log_Msg::program_name_ ?
- ACE_Log_Msg::program_name_ :
- ACE_LIB_TEXT ("<unknown>"));
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp, format,
+ ACE_Log_Msg::program_name_ ?
+ ACE_Log_Msg::program_name_ :
+ ACE_LIB_TEXT ("<unknown>"));
break;
- case 'P': // Format the current process id.
- type = SKIP_SPRINTF;
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%d"),
+
+ case 'P': // Process ID
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("d"));
+ ACE_OS::sprintf (bp, format,
ACE_static_cast (int, this->getpid ()));
break;
- case 'p': // Format the string assocated with the errno value.
+
+ case 'p': // <errno> string, ala perror()
{
- type = SKIP_SPRINTF;
errno = ACE::map_errno (this->errnum ());
if (errno >= 0 && errno < sys_nerr)
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%s: %s"),
- va_arg (argp, ACE_TCHAR *),
- ACE_TEXT_CHAR_TO_TCHAR (ACE_OS_String::strerror (errno)));
+ {
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s: %s"));
+ ACE_OS::sprintf (bp, format,
+ va_arg (argp, ACE_TCHAR *),
+ ACE_TEXT_CHAR_TO_TCHAR (ACE_OS_String::strerror (errno)));
+ }
else
{
#if defined (ACE_WIN32)
@@ -991,35 +1040,42 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
{
const ACE_TCHAR *message =
ACE::sock_error (errno);
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%s: %s"),
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s: %s"));
+ ACE_OS::sprintf (bp, format,
va_arg (argp, const ACE_TCHAR *),
message);
}
else
{
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%s: %s"),
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s: %s"));
+ ACE_OS::sprintf (bp, format,
va_arg (argp, ACE_TCHAR *),
lpMsgBuf);
// Free the buffer.
::LocalFree (lpMsgBuf);
}
#elif !defined (ACE_HAS_WINCE)
+ ACE_OS::strcpy (fp,
+ ACE_LIB_TEXT (
+ "s: <unknown error> = %d"));
ACE_OS::sprintf (bp,
- ACE_LIB_TEXT (
- "%s: <unknown error> = %d"),
+ format,
va_arg (argp, ACE_TCHAR *), errno);
#endif /* ACE_WIN32 */
}
break;
}
+
case 'm': // Format the string assocated with the errno value.
{
- type = SKIP_SPRINTF;
errno = ACE::map_errno (this->errnum ());
if (errno >= 0 && errno < sys_nerr)
- ACE_OS::sprintf (bp,
- ACE_LIB_TEXT ("%s"),
- ACE_OS_String::strerror (errno));
+ {
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp,
+ format,
+ ACE_OS_String::strerror (errno));
+ }
else
{
#if defined (ACE_WIN32)
@@ -1051,19 +1107,20 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
{
const ACE_TCHAR *message =
ACE::sock_error (errno);
- ACE_OS::sprintf (bp,
- ACE_LIB_TEXT ("%s"),
- message);
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp, format, message);
}
else
{
- ACE_OS::sprintf (bp,
- ACE_LIB_TEXT ("%s"),
- lpMsgBuf);
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp, format, lpMsgBuf);
// Free the buffer.
::LocalFree (lpMsgBuf);
}
#elif !defined (ACE_HAS_WINCE)
+ // Ignore the built format... if this is a problem,
+ // this part can be changed to build another string
+ // and pass that with the complete conversion specs.
ACE_OS::sprintf (bp,
ACE_LIB_TEXT ("<unknown error> = %d"),
errno);
@@ -1071,18 +1128,20 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
}
break;
}
+
case 'R': // Format the return status of the operation.
this->op_status (va_arg (argp, int));
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%d"), this->op_status ());
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("d"));
+ ACE_OS::sprintf (bp, format, this->op_status ());
break;
case '{': // Increment the trace_depth, then indent
- type = SKIP_NUL_LOCATE;
+ skip_nul_locate = 1;
(void) this->inc ();
break;
case '}': // indent, then decrement trace_depth
- type = SKIP_NUL_LOCATE;
+ skip_nul_locate = 1;
(void) this->dec ();
break;
@@ -1092,13 +1151,15 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
/* fallthrough */
case 'I': // Indent with nesting_depth*width spaces
- type = SKIP_SPRINTF;
- if (!wpc)
- w[wpc++] = ACE_Trace::get_nesting_indent ();
- w[wpc-1] *= this->trace_depth_;
- ACE_OS::memset (bp, ' ', w[wpc-1]);
- bp += w[wpc - 1];
+ // Caller can do %*I to override nesting indent, and
+ // if %*I was done, wp has the extracted width.
+ if (0 == wp)
+ wp = ACE_Trace::get_nesting_indent ();
+ wp *= this->trace_depth_;
+ ACE_OS::memset (bp, ' ', wp);
+ bp += wp;
*bp = '\0';
+ skip_nul_locate = 1;
break;
case 'r': // Run (invoke) this subroutine.
@@ -1110,7 +1171,6 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
*bp++ = '{';
ACE_Log_Msg::msg_off_ = bp - this->msg_;
- type = SKIP_SPRINTF;
(*va_arg (argp, PTF))();
if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_,
@@ -1120,17 +1180,20 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
*bp++ = '}';
}
*bp = '\0';
-
+ skip_nul_locate = 1;
ACE_Log_Msg::msg_off_ = osave;
break;
}
+
case 'S': // format the string for with this signal number.
{
int sig = va_arg (argp, int);
- type = SKIP_SPRINTF;
#if defined (ACE_HAS_SYS_SIGLIST)
if (sig >= 0 && sig < ACE_NSIG)
- ACE_OS::strcpy (bp, _sys_siglist[sig]);
+ {
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT (s));
+ ACE_OS::sprintf (bp, format, _sys_siglist[sig]);
+ }
else
ACE_OS::sprintf (bp, ACE_LIB_TEXT ("<unknown signal> %d"),
sig);
@@ -1139,32 +1202,35 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
#endif /* ACE_HAS_SYS_SIGLIST */
break;
}
+
case 'D': // Format the timestamp in month/day/year
// hour:minute:sec:usec format.
{
- type = SKIP_SPRINTF;
ACE_TCHAR day_and_time[35];
ACE::timestamp (day_and_time,
sizeof day_and_time);
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%s"), day_and_time);
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp, format, day_and_time);
break;
}
+
case 'T': // Format the timestamp in
// hour:minute:sec:usec format.
{
- type = SKIP_SPRINTF;
ACE_TCHAR day_and_time[35];
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
ACE_OS::sprintf (bp,
- ACE_LIB_TEXT ("%s"),
+ format,
ACE::timestamp (day_and_time,
sizeof day_and_time));
break;
}
+
case 't': // Format thread id.
- type = SKIP_SPRINTF;
#if defined (ACE_WIN32)
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("u"));
ACE_OS::sprintf (bp,
- ACE_LIB_TEXT ("%u"),
+ format,
ACE_static_cast(unsigned,
ACE_Thread::self ()));
#elif defined (AIX) && (ACE_AIX_MINOR_VERS <= 2)
@@ -1178,151 +1244,120 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
// 2. OSF/1 V3.2 has that def, and I'm not sure what affect
// this would have on that.
// -Steve Huston, 19-Aug-97
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%u"), thread_self());
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("u"));
+ ACE_OS::sprintf (bp, format, thread_self());
#elif defined (DIGITAL_UNIX)
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%u"),
-#if defined (ACE_HAS_THREADS)
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("u"));
+ ACE_OS::sprintf (bp, format,
+# if defined (ACE_HAS_THREADS)
pthread_getselfseq_np ()
-#else
+# else
ACE_Thread::self ()
-#endif /* ACE_HAS_THREADS */
+# endif /* ACE_HAS_THREADS */
);
#else
ACE_hthread_t t_id;
ACE_Thread::self (t_id);
# if defined (ACE_HAS_PTHREADS_DRAFT4) && defined (HPUX_10)
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("u"));
// HP-UX 10.x DCE's thread ID is a pointer. Grab the
// more meaningful, readable, thread ID. This will match
// the one seen in the debugger as well.
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%u"),
+ ACE_OS::sprintf (bp, format,
pthread_getunique_np(&t_id));
# elif defined (ACE_MVS)
// MVS's pthread_t is a struct... yuck. So use the ACE 5.0
// code for it.
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%u"), t_id);
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("u"));
+ ACE_OS::sprintf (bp, format, t_id);
# else
// Yes, this is an ugly C-style cast, but the correct
// C++ cast is different depending on whether the t_id
// is an integral type or a pointer type. FreeBSD uses
// a pointer type, but doesn't have a _np function to
// get an integral type, like the OSes above.
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%lu"),
- (unsigned long)t_id);
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("lu"));
+ ACE_OS::sprintf (bp, format, (unsigned long)t_id);
# endif /* ACE_HAS_PTHREADS_DRAFT4 && HPUX_10 */
#endif /* ACE_WIN32 */
break;
- case 's':
+
+ case 's': // String
#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
- type = SKIP_SPRINTF;
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%ls"), va_arg (argp, wchar_t *));
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("ls"));
+ ACE_OS::sprintf (bp, format, va_arg (argp, wchar_t *));
#else /* ACE_WIN32 && ACE_USES_WCHAR */
- type = 1 + wpc;
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
+ ACE_OS::sprintf (bp, format, va_arg (argp, ACE_TCHAR *));
#endif /* ACE_WIN32 && ACE_USES_WCHAR */
break;
- case 'C':
- type = 1 + wpc;
+
+ case 'C': // Char string, Unicode for Win32/WCHAR
#if defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
- fp[1] = 'S';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("S"));
#else /* ACE_WIN32 && ACE_USES_WCHAR */
- fp[1] = 's';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
#endif /* ACE_WIN32 && ACE_USES_WCHAR */
+ ACE_OS::sprintf (bp, format, va_arg (argp, ACE_TCHAR *));
break;
+
case 'W':
- type = 1 + wpc;
#if defined (ACE_WIN32)
# if defined (ACE_USES_WCHAR)
- fp[1] = 's';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("s"));
# else /* ACE_USES_WCHAR */
- fp[1] = 'S';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("S"));
# endif /* ACE_USES_WCHAR */
+ ACE_OS::sprintf (bp, format, va_arg (argp, ACE_TCHAR *));
#elif defined (ACE_HAS_WCHAR)
- type = SKIP_SPRINTF;
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%ls"), va_arg (argp, wchar_t *));
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("ls"));
+ ACE_OS::sprintf (bp, format, va_arg (argp, wchar_t *));
#endif /* ACE_WIN32 / ACE_HAS_WCHAR */
break;
- case 'w':
- type = 4 + wpc;
+
+ case 'w': // Wide character
#if defined (ACE_WIN32)
# if defined (ACE_USES_WCHAR)
- fp[1] = 'c';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("c"));
# else /* ACE_USES_WCHAR */
- fp[1] = 'C';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("C"));
# endif /* ACE_USES_WCHAR */
+ ACE_OS::sprintf (bp, format, va_arg (argp, int));
#elif defined (ACE_USES_WCHAR)
- type = SKIP_SPRINTF;
- ACE_OS::sprintf (bp, ACE_LIB_TEXT ("%lc"), va_arg (argp, wint_t));
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("lc"));
+ ACE_OS::sprintf (bp, format, va_arg (argp, wint_t));
#else /* ACE_WIN32 */
- fp[1] = 'u'; // Since this isn't really supported well
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("u"));
+ ACE_OS::sprintf (bp, format, va_arg (argp, int));
#endif /* ACE_WIN32 */
break;
+
case 'c':
- type = 4 + wpc;
#if defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
- fp[1] = 'C';
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("C"));
+#else
+ ACE_OS::strcpy (fp, ACE_LIB_TEXT ("c"));
#endif /* ACE_WIN32 && ACE_USES_WCHAR */
+ ACE_OS::sprintf (bp, format, va_arg (argp, int));
break;
+
case 'd': case 'i': case 'o':
case 'u': case 'x': case 'X':
- type = 4 + wpc; // 4, 5, 6
+ fp[0] = *format_str;
+ fp[1] = '\0';
+ ACE_OS::sprintf (bp, format, va_arg (argp, int));
break;
+
case 'F': case 'f': case 'e': case 'E':
case 'g': case 'G':
- type = 7 + wpc; // 7, 8, 9
+ fp[0] = *format_str;
+ fp[1] = '\0';
+ ACE_OS::sprintf (bp, format, va_arg (argp, double));
break;
- case 'Q':
- type = 10 + wpc;
- break;
- case '*': // consume width/precision
- w[wpc++] = va_arg (argp, int);
- break;
- default:
- // ?
- break;
- }
- }
-
- if (type != SKIP_SPRINTF)
- {
- c = *format; // Remember char before we overwrite.
- *format = 0; // Overwrite, terminating format.
- switch (type)
- {
- case 1:
- ACE_OS::sprintf (bp, fp, va_arg (argp, ACE_TCHAR *));
- break;
- case 2:
- ACE_OS::sprintf (bp, fp, w[0], va_arg (argp, ACE_TCHAR *));
- bp += w[0];
- type = SKIP_NUL_LOCATE;
- break;
- case 3:
- ACE_OS::sprintf (bp, fp, w[0], w[1],
- va_arg (argp, ACE_TCHAR *));
- bp += w[0];
- type = SKIP_NUL_LOCATE;
- break;
- case 4:
- ACE_OS::sprintf (bp, fp, va_arg (argp, int));
- break;
- case 5:
- ACE_OS::sprintf (bp, fp, w[0], va_arg (argp, int));
- break;
- case 6:
- ACE_OS::sprintf (bp, fp, w[0], w[1], va_arg (argp, int));
- break;
- case 7:
- ACE_OS::sprintf (bp, fp, va_arg (argp, double));
- break;
- case 8:
- ACE_OS::sprintf (bp, fp, w[0], va_arg (argp, double));
- break;
- case 9:
- ACE_OS::sprintf (bp, fp, w[0], w[1], va_arg (argp, double));
- break;
- case 10:
+ case 'Q':
#if defined (ACE_LACKS_LONGLONG_T)
{
// This relies on the ACE_U_LongLong storage layout.
@@ -1335,16 +1370,31 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
ACE_OS::sprintf (bp, "0x%lx", lo);
}
#else /* ! ACE_LACKS_LONGLONG_T */
- ACE_OS::sprintf (bp,
- ACE_UINT64_FORMAT_SPECIFIER,
- va_arg (argp, ACE_UINT64));
+ {
+ const ACE_TCHAR *fmt = ACE_UINT64_FORMAT_SPECIFIER;
+ ACE_OS::strcpy (fp, &fmt[1]); // Skip leading %
+ ACE_OS::sprintf (bp,
+ format,
+ va_arg (argp, ACE_UINT64));
+ }
#endif /* ! ACE_LACKS_LONGLONG_T */
break;
+
+ default:
+ // So, it's not a legit format specifier after all...
+ // Copy from the original % to where we are now, then
+ // continue with whatever comes next.
+ while (start_format != format_str)
+ *bp++ = *start_format++;
+ *bp++ = *format_str;
+ break;
}
- *format = c; // Restore char we overwrote.
+
+ // Bump to the next char in the caller's format_str
+ format_str++;
}
- if (type != SKIP_NUL_LOCATE)
+ if (!skip_nul_locate)
while (*bp != '\0') // Locate end of bp.
bp++;
}
@@ -1352,8 +1402,6 @@ ACE_Log_Msg::log (const ACE_TCHAR *format_str,
*bp = '\0'; // Terminate bp, but don't auto-increment this!
- ACE_OS::free (ACE_MALLOC_T (save_p));
-
// Check that memory was not corrupted.
if (bp >= this->msg_ + ACE_Log_Record::MAXLOGMSGLEN)
{
diff --git a/tests/Log_Msg_Test.cpp b/tests/Log_Msg_Test.cpp
index e5c9c44f0c1..ab789855ba1 100644
--- a/tests/Log_Msg_Test.cpp
+++ b/tests/Log_Msg_Test.cpp
@@ -410,12 +410,116 @@ test_ostream (void)
return 0;
}
+
+// For testing the format specifiers, a class is defined as a callback
+// mechanism. It will get the formatted messages and check them for
+// correctness. The test_format_specs() function will set the first
+// few characters to say which test is being run, and the Log_Spec_Verify
+// class will use that to decide how to verify the results.
+
+class Log_Spec_Verify : public ACE_Log_Msg_Callback
+{
+public:
+ Log_Spec_Verify () : fail_ (0) {};
+
+ void log (ACE_Log_Record &log_record);
+ // Logging callback
+
+ int result ();
+
+private:
+ int fail_;
+ // Count how many tests failed.
+};
+
+void
+Log_Spec_Verify::log (ACE_Log_Record &log_record)
+{
+ ACE_TCHAR *b = log_record.msg_data ();
+ const ACE_TCHAR *expect;
+
+ if (ACE_OS::strncmp (b, ACE_TEXT ("l1:"), 3) == 0)
+ {
+ expect = ACE_TEXT ("42");
+ b += 4; //3
+ }
+ else if (ACE_OS::strncmp (b, ACE_TEXT ("l2:"), 3) == 0)
+ {
+ expect = ACE_TEXT (" 42");
+ b += 3;
+ }
+ else if (ACE_OS::strncmp (b, ACE_TEXT ("l3N1:"), 4) == 0)
+ {
+ expect = ACE_TEXT ("0042,Log_Msg");
+ b += 4;
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Log_Spec_Verify, unrecognized test: %s\n"),
+ b));
+ this->fail_++;
+ }
+
+ if (b != log_record.msg_data () && ACE_OS::strcmp (b, expect) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Test %s failed; expected %s\n"),
+ log_record.msg_data (), expect));
+ this->fail_++;
+ }
+
+ return;
+}
+
+int
+Log_Spec_Verify::result ()
+{
+ if (this->fail_ == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("All logging specifier tests passed.\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%d logging specifier tests failed!\n"),
+ this->fail_));
+ return this->fail_;
+}
+
+static int
+test_format_specs ()
+{
+#if 0
+ Log_Spec_Verify verifier;
+ ACE_Log_Msg logger;
+
+ if (logger.open (ACE_TEXT ("Log_Msg_Test"), ACE_Log_Msg::MSG_CALLBACK) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("%T: test_format_specs open")),
+ 1);
+ logger.msg_callback (&verifier);
+
+ logger.linenum (42);
+ logger.file (ACE_TEXT ("Log_Msg_Test.cpp"));
+ logger.log (LM_DEBUG, ACE_TEXT ("l1:%l"));
+ logger.log (LM_DEBUG, ACE_TEXT ("l2:%5l"));
+ logger.log (LM_DEBUG, ACE_TEXT ("l3N1:%0*l,%.7N"), 4);
+ return verifier.result ();
+#else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("l1:%l\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("l2:%5l\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("l3N1:%0*l,%.7N\n"), 4));
+ return 0;
+#endif
+
+}
+
+
// Main function.
int
main (int, ACE_TCHAR *argv[])
{
ACE_START_TEST (ACE_TEXT ("Log_Msg_Test"));
+
+ int status = 0;
+
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("**** running ostream test\n")));
@@ -435,11 +539,18 @@ main (int, ACE_TCHAR *argv[])
// Test various features of the <ACE_Log_Msg>.
test_log_msg_features (argv[0]);
- // Restore this mask so the shutdown message will print correctly!
+ // Test the format specifiers
+
+ // Restore this mask so diags and the shutdown message will print correctly!
ACE_LOG_MSG->priority_mask (ACE_LOG_MSG->priority_mask () | LM_DEBUG,
ACE_Log_Msg::PROCESS);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** running format specifiers test\n")));
+ if (test_format_specs () != 0)
+ status = 1;
+
ACE_END_TEST;
- return 0;
+ return status;
}
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)