[Ace-users] [ace-users] Proposal: ACE_OS::asprintf(), etc.

Johnny Willemsen jwillemsen at remedy.nl
Fri Oct 26 14:10:22 CDT 2007


Hi JT,

Added asprintf() as wrapper is ok. The patch hard to review, a lot of checks
for defines are removed, if you make sure that things keep working for all
tests and users, feel free to commit this, but keep a very good watch at the
scoreboard. 

Regards,

Johnny Willemsen
Remedy IT
Postbus 101
2650 AC  Berkel en Rodenrijs
The Netherlands
www.theaceorb.nl / www.remedy.nl  

*** Integrated compile and test statistics see
http://scoreboard.theaceorb.nl ***
*** Commercial service and support for ACE/TAO/CIAO             ***
*** See http://www.theaceorb.nl/en/support.html                 ***

> Similar to the getprogname() issue I mentioned yesterday, another
> thing we ran into while porting our system from NetBSD to Solaris 
> was the use of asprintf() and vasprintf().
> 
> asprintf() is similar to sprintf(), but instead of passing a char *
> you pass the address of a char*, which is set to a malloc() buffer
> containing the formatted output.  This is useful in cases where you
> don't know the size of the buffer needed. While you can do the same
> thing with two calls to snprintf() -- the first to find the buffer
> size, the second to format the string into an appropriately sized
> buffer -- asprintf() nicely ties this together in a single call.
> 
> The asprintf(), etc. functions are fairly widely implemented: *BSD,
> Linux, etc.  It appears they may even become part of the C standard
> some time in the future. While preparing this message, I googled up a
> *.pdf of C Standard Committee Draft N1248 --- See
> http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1248.pdf for details.
> 
> I think that adding ACE_OS::asprintf() wrapper facades would be
> generally useful.
> 
> While implementing these functions, I noticed some anomalies in some
> of the other ACE_OS::*printf() wrapper facades:
> 
>  * There was no wide character version of ACE_OS::printf().
> 
>  * There were no wide or narrow versions of ACE_OS::vprintf().
> 
>  * There were no wide or narrow versions of ACE_OS::vfprintf().
> 
>  * In some cases, ACE_OS::*printf() was implemented in terms of the
>    corresponding ACE_OS::v*printf() function; in others it was done 
>    in terms of the system's ::v*printf() function. 
> 
>    Some of this was because of missing ACE_OS::vprintf() and
>    ACE_OS::vfprintf() as noted above.  But now that I've added those
>    functions, I changed ACE_OS::*printf() to use ACE_OS::v*printf().
>    This ensures consistent behavior (ACE_OS::{v,}s{n,}printf() has
>    a pretty complicated nest of conditionals, and the code appears
>    to have diverged (hopefully only syntactically) over the years).
> 
>    In most cases, ACE_OS::v*printf() is an inline that simply invokes
>    ::v*printf(), so there should be no time or space overhead.
> 
> Here is the patch I'm proposing.
> 
>     --jtc
> 
> Index: OS_NS_stdio.cpp
> ===================================================================
> --- OS_NS_stdio.cpp	(revision 79869)
> +++ OS_NS_stdio.cpp	(working copy)
> @@ -257,14 +257,17 @@
>  
>  #endif /* ACE_WIN32 */
>  
> +// The following *printf functions aren't inline because
> +// they use varargs.
> +
>  int
>  ACE_OS::fprintf (FILE *fp, const char *format, ...)
>  {
> -  ACE_OS_TRACE ("ACE_OS::fprintf");
> +  // ACE_OS_TRACE ("ACE_OS::fprintf");
>    int result = 0;
>    va_list ap;
>    va_start (ap, format);
> -  ACE_OSCALL (::vfprintf (fp, format, ap), int, -1, result);
> +  result = ACE_OS::vfprintf (fp, format, ap);
>    va_end (ap);
>    return result;
>  }
> @@ -273,28 +276,41 @@
>  int
>  ACE_OS::fprintf (FILE *fp, const wchar_t *format, ...)
>  {
> -  ACE_OS_TRACE ("ACE_OS::fprintf");
> -
> -# if !defined (ACE_HAS_VFWPRINTF)
> -  ACE_UNUSED_ARG (fp);
> -  ACE_UNUSED_ARG (format);
> -  ACE_NOTSUP_RETURN (-1);
> -
> -# else
> +  // ACE_OS_TRACE ("ACE_OS::fprintf");
>    int result = 0;
>    va_list ap;
>    va_start (ap, format);
> -  ACE_OSCALL (ACE_STD_NAMESPACE::vfwprintf (fp, format, ap), 
> int, -1, result);
> +  result = ACE_OS::vfprintf (fp, format, ap);
>    va_end (ap);
>    return result;
> -
> -# endif /* ACE_HAS_VFWPRINTF */
>  }
>  #endif /* ACE_HAS_WCHAR */
>  
> +int
> +ACE_OS::asprintf (char **bufp, const char *format, ...)
> +{
> +  // ACE_OS_TRACE ("ACE_OS::aprintf");
> +  int result;
> +  va_list ap;
> +  va_start (ap, format);
> +  result = ACE_OS::vasprintf (bufp, format, ap);
> +  va_end (ap);
> +  return result;
> +}
>  
> -// The following *printf functions aren't inline because
> -// they use varargs.
> +#if defined (ACE_HAS_WCHAR)
> +int
> +ACE_OS::asprintf (wchar_t **bufp, const wchar_t *format, ...)
> +{
> +  // ACE_OS_TRACE ("ACE_OS::aprintf");
> +  int result;
> +  va_list ap;
> +  va_start (ap, format);
> +  result = ACE_OS::vasprintf (bufp, format, ap);
> +  va_end (ap);
> +  return result;
> +}
> +#endif /* ACE_HAS_WCHAR */
>  
>  int
>  ACE_OS::printf (const char *format, ...)
> @@ -303,12 +319,26 @@
>    int result;
>    va_list ap;
>    va_start (ap, format);
> -  ACE_OSCALL (::vprintf (format, ap), int, -1, result);
> +  result = ACE_OS::vprintf (format, ap);
>    va_end (ap);
>    return result;
>  }
>  
> +#if defined (ACE_HAS_WCHAR)
>  int
> +ACE_OS::printf (const wchar_t *format, ...)
> +{
> +  // ACE_OS_TRACE ("ACE_OS::printf");
> +  int result;
> +  va_list ap;
> +  va_start (ap, format);
> +  result = ACE_OS::vprintf (format, ap);
> +  va_end (ap);
> +  return result;
> +}
> +#endif /* ACE_HAS_WCHAR */
> +
> +int
>  ACE_OS::snprintf (char *buf, size_t maxlen, const char *format, ...)
>  {
>    // ACE_OS_TRACE ("ACE_OS::snprintf");
> @@ -321,53 +351,16 @@
>  }
>  
>  #if defined (ACE_HAS_WCHAR)
> -
>  int
>  ACE_OS::snprintf (wchar_t *buf, size_t maxlen, const wchar_t 
> *format, ...)
>  {
>    // ACE_OS_TRACE ("ACE_OS::snprintf");
> -# if (defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 500) || \
> -     (defined (sun) && !defined (_XPG4) || defined(_XPG5)) || \
> -     defined (ACE_WIN32) || defined (ACE_HAS_VSWPRINTF)
>    int result;
>    va_list ap;
>    va_start (ap, format);
> -#  if 0 /* defined (ACE_HAS_TR24731_2005_CRT) */
> -  // _vsnwprintf_s() doesn't report the length needed when 
> it truncates. This
> -  // info is needed for the API contract return value, so 
> don't use this.
> -  // There's adequate protection via the maxlen.
> -  result = _vsnwprintf_s (buf, maxlen, _TRUNCATE, format, ap);
> -#  elif defined (ACE_WIN32)
> -  // Microsoft's vswprintf() doesn't have the maxlen argument that
> -  // XPG4/UNIX98 define. They do, however, recommend use of 
> _vsnwprintf()
> -  // as a substitute, which does have the same signature as 
> the UNIX98 one.
> -  ACE_OSCALL (::_vsnwprintf (buf, maxlen, format, ap), int, 
> -1, result);
> -  // Win32 doesn't regard a full buffer with no 0-terminate 
> as an overrun.
> -  if (result == static_cast <int> (maxlen))
> -    result = -1;
> -
> -  // Win32 doesn't 0-terminate the string if it overruns maxlen.
> -  if (result == -1)
> -    buf[maxlen-1] = '\0';
> -#  else
> -  ACE_OSCALL (::vswprintf (buf, maxlen, format, ap), int, 
> -1, result);
> -#  endif /* ACE_WIN32 */
> +  result = ACE_OS::vsnprintf (buf, maxlen, format, ap);
>    va_end (ap);
> -  // In out-of-range conditions, C99 defines vsnprintf to 
> return the number
> -  // of characters that would have been written if enough 
> space was available.
> -  // Earlier variants of the vsnprintf() (e.g. UNIX98) 
> defined it to return
> -  // -1. This method follows the C99 standard, but needs to 
> guess at the
> -  // value; uses maxlen + 1.
> -  if (result == -1)
> -    result = static_cast <int> (maxlen + 1);
>    return result;
> -
> -# else
> -  ACE_UNUSED_ARG (buf);
> -  ACE_UNUSED_ARG (maxlen);
> -  ACE_UNUSED_ARG (format);
> -  ACE_NOTSUP_RETURN (-1);
> -# endif /* _XOPEN_SOURCE ...  */
>  }
>  #endif /* ACE_HAS_WCHAR */
>  
> @@ -375,11 +368,10 @@
>  ACE_OS::sprintf (char *buf, const char *format, ...)
>  {
>    // ACE_OS_TRACE ("ACE_OS::sprintf");
> -
>    int result;
>    va_list ap;
>    va_start (ap, format);
> -  ACE_OSCALL (::vsprintf (buf, format, ap), int, -1, result);
> +  result = ACE_OS::vsprintf (buf, format, ap);
>    va_end (ap);
>    return result;
>  }
> @@ -388,46 +380,77 @@
>  int
>  ACE_OS::sprintf (wchar_t *buf, const wchar_t *format, ...)
>  {
> -  ACE_OS_TRACE ("ACE_OS::sprintf");
> -
> -# if (defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 500) || \
> -     (defined (sun) && !defined (_XPG4) || defined(_XPG5)) || \
> -      defined (ACE_HAS_DINKUM_STL) || defined (__DMC__) || \
> -      defined (ACE_HAS_VSWPRINTF) || \
> -     (defined (ACE_WIN32_VC8) && !defined (ACE_HAS_WINCE) && \
> -      _MSC_FULL_VER > 140050000)
> -
> -  // The XPG4/UNIX98/C99 signature of the wide-char sprintf has a
> -  // maxlen argument. Since this method doesn't supply one, pass in
> -  // a length that works (ULONG_MAX doesn't on all platform 
> since some check
> -  // to see if the operation will remain in bounds). If this 
> isn't ok, use
> -  // ACE_OS::snprintf().
> +  // ACE_OS_TRACE ("ACE_OS::sprintf");
>    int result;
>    va_list ap;
>    va_start (ap, format);
> -  ACE_OSCALL (ACE_STD_NAMESPACE::vswprintf (buf, 4096, 
> format, ap), int, -1, result);
> +  result = ACE_OS::vsprintf (buf, format, ap);
>    va_end (ap);
>    return result;
> +}
> +#endif /* ACE_HAS_WCHAR */
>  
> -# elif defined (ACE_WIN32)
> -  // Pre-VC8 Windows has vswprintf, but the signature is 
> from the older ISO C
> -  // standard. Also see ACE_OS::snprintf() for more info on this.
> +#if !defined (ACE_HAS_VASPRINTF)
> +int
> +ACE_OS::vasprintf_emulation(char **bufp, const char *format, 
> va_list argptr)
> +{
> +  int size;
>  
> -  int result;
>    va_list ap;
> -  va_start (ap, format);
> -  ACE_OSCALL (::vswprintf (buf, format, ap), int, -1, result);
> +  va_copy (ap, argptr);
> +  size = ACE_OS::vsnprintf(NULL, 0, format, ap);
>    va_end (ap);
> -  return result;
>  
> -# else
> +  if (size != -1) 
> +    {
> +      char *buf = reinterpret_cast<char*>(ACE_OS::malloc(size + 1));
> +      if (!buf)
> +	return -1;
>  
> -  ACE_UNUSED_ARG (buf);
> -  ACE_UNUSED_ARG (format);
> -  ACE_NOTSUP_RETURN (-1);
> +      va_list aq;
> +      va_copy (aq, argptr);
> +      size = ACE_OS::vsnprintf(buf, size + 1, format, aq);
> +      va_end (aq);
>  
> -# endif /* XPG5 || ACE_HAS_DINKUM_STL */
> +      if (size != -1)
> +        *bufp = buf;
> +    }
> +
> +  return size;
>  }
> +#endif /* !ACE_HAS_VASPRINTF */
> +
> +#if defined (ACE_HAS_WCHAR)
> +#if !defined (ACE_HAS_VASWPRINTF)
> +int
> +ACE_OS::vaswprintf_emulation(wchar_t **bufp, const wchar_t 
> *format, va_list argptr)
> +{
> +  int size;
> +
> +  va_list ap;
> +  va_copy (ap, argptr);
> +  size = ACE_OS::vsnprintf(NULL, 0, format, ap);
> +  va_end (ap);
> +
> +  if (size != -1) 
> +    {
> +      wchar_t *buf = reinterpret_cast<wchar_t*>
> +	(ACE_OS::malloc((size + 1) * sizeof(wchar_t)));
> +      if (!buf)
> +	return -1;
> +
> +      va_list aq;
> +      va_copy (aq, argptr);
> +      size = ACE_OS::vsnprintf(buf, size + 1, format, aq);
> +      va_end (aq);
> +
> +      if (size != -1)
> +        *bufp = buf;
> +    }
> +
> +  return size;
> +}
> +#endif /* !ACE_HAS_VASWPRINTF */
>  #endif /* ACE_HAS_WCHAR */
>  
>  ACE_END_VERSIONED_NAMESPACE_DECL
> Index: OS_NS_stdio.h
> ===================================================================
> --- OS_NS_stdio.h	(revision 79869)
> +++ OS_NS_stdio.h	(working copy)
> @@ -208,6 +208,14 @@
>  # endif /* ACE_LACKS_CUSERID */
>    //@}
>  
> +  extern ACE_Export
> +  int asprintf (char **bufp, const char* format, ...);
> +
> +# if defined (ACE_HAS_WCHAR)
> +  extern ACE_Export
> +  int asprintf (wchar_t **bufp, const wchar_t* format, ...);
> +#endif /* ACE_HAS_WCHAR */
> +
>    ACE_NAMESPACE_INLINE_FUNCTION
>    int fclose (FILE *fp);
>  
> @@ -408,6 +416,11 @@
>    extern ACE_Export
>    int printf (const char *format, ...);
>  
> +#if defined (ACE_HAS_WCHAR)
> +  extern ACE_Export
> +  int printf (const wchar_t *format, ...);
> +#endif
> +
>    ACE_NAMESPACE_INLINE_FUNCTION
>    int puts (const char *s);
>  
> @@ -458,6 +471,15 @@
>  #endif /* ACE_HAS_WCHAR */
>  
>    ACE_NAMESPACE_INLINE_FUNCTION
> +  int vasprintf (char **bufp, const char *format, va_list argptr);
> +
> +  ACE_NAMESPACE_INLINE_FUNCTION
> +  int vprintf (const char *format, va_list argptr);
> +
> +  ACE_NAMESPACE_INLINE_FUNCTION
> +  int vfprintf (FILE *fp, const char *format, va_list argptr);
> +
> +  ACE_NAMESPACE_INLINE_FUNCTION
>    int vsprintf (char *buffer, const char *format, va_list argptr);
>  
>    ACE_NAMESPACE_INLINE_FUNCTION
> @@ -465,12 +487,33 @@
>  
>  # if defined (ACE_HAS_WCHAR)
>    ACE_NAMESPACE_INLINE_FUNCTION
> +  int vasprintf (wchar_t **bufp, const wchar_t *format, 
> va_list argptr);
> +
> +  ACE_NAMESPACE_INLINE_FUNCTION
> +  int vprintf (const wchar_t *format, va_list argptr);
> +
> +  ACE_NAMESPACE_INLINE_FUNCTION
> +  int vfprintf (FILE *fp, const wchar_t *format, va_list argptr);
> +
> +  ACE_NAMESPACE_INLINE_FUNCTION
>    int vsprintf (wchar_t *buffer, const wchar_t *format, 
> va_list argptr);
>  
>    ACE_NAMESPACE_INLINE_FUNCTION
>    int vsnprintf (wchar_t *buffer, size_t maxlen, const 
> wchar_t *format, va_list argptr);
>  # endif /* ACE_HAS_WCHAR */
>  
> +#if !defined (ACE_HAS_VASPRINTF)
> +  extern ACE_Export
> +  int vasprintf_emulation (char **bufp, const char *format, 
> va_list argptr); 
> +#endif /* !ACE_HAS_VASPRINTF */
> +
> +#if defined (ACE_HAS_WCHAR)
> +#if !defined (ACE_HAS_VASWPRINTF)
> +  extern ACE_Export
> +  int vaswprintf_emulation (wchar_t **bufp, const wchar_t 
> *format, va_list argptr);
> +#endif /* !ACE_HAS_VASWPRINTF */
> +#endif /* ACE_HAS_WCHAR */
> +
>  } /* namespace ACE_OS */
>  
>  ACE_END_VERSIONED_NAMESPACE_DECL
> Index: OS_NS_stdio.inl
> ===================================================================
> --- OS_NS_stdio.inl	(revision 79869)
> +++ OS_NS_stdio.inl	(working copy)
> @@ -949,6 +949,69 @@
>  #endif /* ACE_HAS_WCHAR */
>  
>  ACE_INLINE int
> +ACE_OS::vasprintf (char **bufp, const char* format, va_list argptr)
> +{
> +#if defined (ACE_HAS_VASPRINTF)
> +  return ::vasprintf (bufp, format, argptr);
> +#else
> +  return ACE_OS::vasprintf_emulation (bufp, format, argptr); 
> +#endif /* ACE_HAS_VASPRINTF */
> +}
> +
> +#if defined (ACE_HAS_WCHAR)
> +ACE_INLINE int
> +ACE_OS::vasprintf (wchar_t **bufp, const wchar_t* format, 
> va_list argptr)
> +{
> +#if defined (ACE_HAS_VASWPRINTF)
> +  return ::vaswprintf (bufp, format, argptr);
> +#else
> +  return ACE_OS::vaswprintf_emulation (bufp, format, argptr);
> +#endif /* ACE_HAS_VASWPRINTF */
> +}
> +#endif /* ACE_HAS_WCHAR */
> +
> +ACE_INLINE int
> +ACE_OS::vprintf (const char *format, va_list argptr)
> +{
> +  return ::vprintf (format, argptr);
> +}
> +
> +#if defined (ACE_HAS_WCHAR)
> +ACE_INLINE int
> +ACE_OS::vprintf (const wchar_t *format, va_list argptr)
> +{
> +#if defined (ACE_HAS_VWPRINTF)
> +  return ::vwprintf (format, argptr);
> +#else
> +  ACE_UNUSED_ARG (format);
> +  ACE_UNUSED_ARG (argptr);
> +  ACE_NOTSUP_RETURN (-1);
> +#endif /* ACE_HAS_VWPRINTF */
> +}
> +#endif /* ACE_HAS_WCHAR */
> +
> +ACE_INLINE int
> +ACE_OS::vfprintf (FILE *fp, const char *format, va_list argptr)
> +{
> +  return ::vfprintf (fp, format, argptr);
> +}
> +
> +#if defined (ACE_HAS_WCHAR)
> +ACE_INLINE int
> +ACE_OS::vfprintf (FILE *fp, const wchar_t *format, va_list argptr)
> +{
> +#if defined (ACE_HAS_VFWPRINTF)
> +  return ::vfwprintf (fp, format, argptr);
> +#else
> +  ACE_UNUSED_ARG (fp);
> +  ACE_UNUSED_ARG (format);
> +  ACE_UNUSED_ARG (argptr);
> +  ACE_NOTSUP_RETURN (-1);
> +#endif /* ACE_HAS_VFWPRINTF */
> +}
> +#endif /* ACE_HAS_WCHAR */
> +
> +ACE_INLINE int
>  ACE_OS::vsprintf (char *buffer, const char *format, va_list argptr)
>  {
>    return ::vsprintf (buffer, format, argptr);
> 
>  
> -- 
> J.T. Conklin
> 
> _______________________________________________
> ace-users mailing list
> ace-users at mail.cse.wustl.edu
> http://mail.cse.wustl.edu/mailman/listinfo/ace-users
> 



More information about the Ace-users mailing list