Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / OS_NS_stdio.cpp
blob76db871d18de3a97f43f366b29ea08b22bacf9b8
1 #include "ace/OS_NS_stdio.h"
2 #include "ace/OS_NS_Thread.h"
4 #if !defined (ACE_HAS_INLINED_OSCALLS)
5 # include "ace/OS_NS_stdio.inl"
6 #endif /* ACE_HAS_INLINED_OSCALLS */
8 #if !defined (ACE_LACKS_STDINT_H)
9 # include <stdint.h>
10 #endif
12 #include "ace/Malloc_Base.h"
14 #include <cctype>
15 #include <clocale>
16 #include <cmath>
18 #ifndef ACE_LACKS_WCHAR_H
19 # include <cwchar>
20 #endif
22 # if defined (ACE_WIN32)
24 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
25 ACE_TEXT_OSVERSIONINFO ACE_OS::win32_versioninfo_;
26 HINSTANCE ACE_OS::win32_resource_module_;
27 ACE_END_VERSIONED_NAMESPACE_DECL
29 # if defined (ACE_HAS_DLL) && (ACE_HAS_DLL == 1)
30 // This function is called by the OS when the ACE DLL is loaded. We
31 // use it to determine the default module containing ACE's resources.
32 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
34 if (reason == DLL_PROCESS_ATTACH)
36 # if defined (ACE_DISABLES_THREAD_LIBRARY_CALLS) && (ACE_DISABLES_THREAD_LIBRARY_CALLS == 1)
37 ::DisableThreadLibraryCalls (instance);
38 # endif /* ACE_DISABLES_THREAD_LIBRARY_CALLS */
39 ACE_OS::set_win32_resource_module(instance);
41 else if (reason == DLL_THREAD_DETACH)
43 ACE_OS::cleanup_tss (0);
45 return TRUE;
47 # endif /* ACE_HAS_DLL && ACE_HAS_DLL == 1 */
48 # endif /* ACE_WIN32 */
50 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
52 namespace ACE_OS
54 void
55 ace_flock_t::dump () const
57 #if defined (ACE_HAS_DUMP)
58 ACE_OS_TRACE ("ACE_OS::ace_flock_t::dump");
60 # if 0
61 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
62 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("handle_ = %u"), this->handle_));
63 # if defined (ACE_WIN32)
64 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nInternal = %d"),
65 this->overlapped_.Internal));
66 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nInternalHigh = %d"),
67 this->overlapped_.InternalHigh));
68 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nOffsetHigh = %d"),
69 this->overlapped_.OffsetHigh));
70 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nhEvent = %d"),
71 this->overlapped_.hEvent));
72 # else
73 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_whence = %d"),
74 this->lock_.l_whence));
75 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_start = %d"), this->lock_.l_start));
76 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_len = %d"), this->lock_.l_len));
77 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_type = %d"), this->lock_.l_type));
78 # endif /* ACE_WIN32 */
79 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
80 # endif /* 0 */
81 #endif /* ACE_HAS_DUMP */
84 } /* namespace ACE_OS */
86 /*****************************************************************************/
89 #if defined (ACE_WIN32)
90 namespace
92 /// Translate fopen's mode char to open's mode. This helper function
93 /// is here to avoid maintaining several pieces of identical code.
94 void
95 fopen_mode_to_open_mode_converter (ACE_TCHAR x, int & hmode)
97 switch (x)
99 case ACE_TEXT ('r'):
100 if (ACE_BIT_DISABLED (hmode, _O_RDWR))
102 ACE_CLR_BITS (hmode, _O_WRONLY);
103 ACE_SET_BITS (hmode, _O_RDONLY);
105 break;
106 case ACE_TEXT ('w'):
107 if (ACE_BIT_DISABLED (hmode, _O_RDWR))
109 ACE_CLR_BITS (hmode, _O_RDONLY);
110 ACE_SET_BITS (hmode, _O_WRONLY);
112 ACE_SET_BITS (hmode, _O_CREAT | _O_TRUNC);
113 break;
114 case ACE_TEXT ('a'):
115 if (ACE_BIT_DISABLED (hmode, _O_RDWR))
117 ACE_CLR_BITS (hmode, _O_RDONLY);
118 ACE_SET_BITS (hmode, _O_WRONLY);
120 ACE_SET_BITS (hmode, _O_CREAT | _O_APPEND);
121 break;
122 case ACE_TEXT ('+'):
123 ACE_CLR_BITS (hmode, _O_RDONLY | _O_WRONLY);
124 ACE_SET_BITS (hmode, _O_RDWR);
125 break;
126 case ACE_TEXT ('t'):
127 ACE_CLR_BITS (hmode, _O_BINARY);
128 ACE_SET_BITS (hmode, _O_TEXT);
129 break;
130 case ACE_TEXT ('b'):
131 ACE_CLR_BITS (hmode, _O_TEXT);
132 ACE_SET_BITS (hmode, _O_BINARY);
133 break;
136 } // Close anonymous namespace
138 FILE *
139 ACE_OS::fopen (const char *filename,
140 const ACE_TCHAR *mode)
142 ACE_OS_TRACE ("ACE_OS::fopen");
143 #if defined (ACE_LACKS_FOPEN)
144 ACE_UNUSED_ARG (filename);
145 ACE_UNUSED_ARG (mode);
146 ACE_NOTSUP_RETURN (0);
147 #else
148 int hmode = _O_TEXT;
150 // Let the chips fall where they may if the user passes in a NULL
151 // mode string. Convert to an empty mode string to prevent a
152 // crash.
153 ACE_TCHAR const empty_mode[] = ACE_TEXT ("");
154 if (!mode)
155 mode = empty_mode;
157 for (ACE_TCHAR const* mode_ptr = mode; *mode_ptr != 0; ++mode_ptr)
158 fopen_mode_to_open_mode_converter (*mode_ptr, hmode);
160 ACE_HANDLE const handle = ACE_OS::open (filename, hmode);
161 if (handle != ACE_INVALID_HANDLE)
163 hmode &= _O_TEXT | _O_RDONLY | _O_APPEND;
165 int const fd = ::_open_osfhandle (intptr_t (handle), hmode);
167 if (fd != -1)
169 # if defined (ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)
170 FILE * const fp = ::_fdopen (fd, const_cast<ACE_TCHAR *> (mode));
171 # elif defined (ACE_HAS_NONCONST_FDOPEN) && defined (ACE_USES_WCHAR)
172 FILE * const fp = ::_wfdopen (fd, const_cast<ACE_TCHAR *> (mode));
173 # elif defined (ACE_USES_WCHAR)
174 FILE * const fp = ::_wfdopen (fd, mode);
175 # else
176 FILE * const fp = ::fdopen (fd, mode);
177 # endif /* defined(ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)) */
178 if (fp != 0)
180 return fp;
182 ::_close (fd);
185 ACE_OS::close (handle);
187 return 0;
188 #endif
191 #if defined (ACE_HAS_WCHAR)
192 FILE *
193 ACE_OS::fopen (const char *filename,
194 const ACE_ANTI_TCHAR *mode)
196 return ACE_OS::fopen (filename, ACE_TEXT_ANTI_TO_TCHAR (mode));
199 FILE *
200 ACE_OS::fopen (const wchar_t *filename,
201 const ACE_ANTI_TCHAR *mode)
203 return ACE_OS::fopen (filename, ACE_TEXT_ANTI_TO_TCHAR (mode));
206 FILE *
207 ACE_OS::fopen (const wchar_t *filename,
208 const ACE_TCHAR *mode)
210 ACE_OS_TRACE ("ACE_OS::fopen");
211 #if defined (ACE_LACKS_FOPEN)
212 ACE_UNUSED_ARG (filename);
213 ACE_UNUSED_ARG (mode);
214 ACE_NOTSUP_RETURN (0);
215 #else
216 int hmode = _O_TEXT;
218 for (const ACE_TCHAR *mode_ptr = mode; *mode_ptr != 0; mode_ptr++)
219 fopen_mode_to_open_mode_converter (*mode_ptr, hmode);
221 ACE_HANDLE handle = ACE_OS::open (filename, hmode);
222 if (handle != ACE_INVALID_HANDLE)
224 hmode &= _O_TEXT | _O_RDONLY | _O_APPEND;
226 int const fd = ::_open_osfhandle (intptr_t (handle), hmode);
228 if (fd != -1)
230 # if defined (ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)
231 FILE *fp = ::_fdopen (fd, const_cast<char *> (mode));
232 # elif defined (ACE_HAS_NONCONST_FDOPEN) && defined (ACE_USES_WCHAR)
233 FILE *fp = ::_wfdopen (fd, const_cast<wchar_t *> (mode));
234 # elif defined (ACE_USES_WCHAR)
235 FILE *fp = ::_wfdopen (fd, mode);
236 # else
237 FILE *fp = ::fdopen (fd, mode);
238 # endif /* defined(ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)) */
239 if (fp != 0)
241 return fp;
243 ::_close (fd);
246 ACE_OS::close (handle);
248 return 0;
249 #endif
251 #endif /* ACE_HAS_WCHAR */
253 #endif /* ACE_WIN32 */
255 #ifndef ACE_STDIO_USE_STDLIB_FOR_VARARGS
256 // The following *printf functions aren't inline because
257 // they use varargs.
259 ACE_OS::fprintf (FILE *fp, const char *format, ...)
261 // ACE_OS_TRACE ("ACE_OS::fprintf");
262 #if defined (ACE_LACKS_VA_FUNCTIONS)
263 ACE_UNUSED_ARG (fp);
264 ACE_UNUSED_ARG (format);
265 ACE_NOTSUP_RETURN (-1);
266 #else
267 va_list ap;
268 va_start (ap, format);
269 int const result = ACE_OS::vfprintf (fp, format, ap);
270 va_end (ap);
271 return result;
272 #endif /* ACE_LACKS_VA_FUNCTIONS */
274 #endif /* ACE_STDIO_USE_STDLIB_FOR_VARARGS */
276 #if defined (ACE_HAS_WCHAR)
278 ACE_OS::fprintf (FILE *fp, const wchar_t *format, ...)
280 // ACE_OS_TRACE ("ACE_OS::fprintf");
281 #if defined (ACE_LACKS_VA_FUNCTIONS)
282 ACE_UNUSED_ARG (fp);
283 ACE_UNUSED_ARG (format);
284 ACE_NOTSUP_RETURN (-1);
285 #else
286 va_list ap;
287 va_start (ap, format);
288 int const result = ACE_OS::vfprintf (fp, format, ap);
289 va_end (ap);
290 return result;
291 #endif /* ACE_LACKS_VA_FUNCTIONS */
293 #endif /* ACE_HAS_WCHAR */
296 ACE_OS::asprintf (char **bufp, const char *format, ...)
298 // ACE_OS_TRACE ("ACE_OS::asprintf");
299 #if defined (ACE_LACKS_VA_FUNCTIONS)
300 ACE_UNUSED_ARG (bufp);
301 ACE_UNUSED_ARG (format);
302 ACE_NOTSUP_RETURN (-1);
303 #else
304 va_list ap;
305 va_start (ap, format);
306 int const result = ACE_OS::vasprintf (bufp, format, ap);
307 va_end (ap);
308 return result;
309 #endif /* ACE_LACKS_VA_FUNCTIONS */
312 #if defined (ACE_HAS_WCHAR)
314 ACE_OS::asprintf (wchar_t **bufp, const wchar_t *format, ...)
316 // ACE_OS_TRACE ("ACE_OS::asprintf");
317 #if defined (ACE_LACKS_VA_FUNCTIONS)
318 ACE_UNUSED_ARG (bufp);
319 ACE_UNUSED_ARG (format);
320 ACE_NOTSUP_RETURN (-1);
321 #else
322 va_list ap;
323 va_start (ap, format);
324 int const result = ACE_OS::vasprintf (bufp, format, ap);
325 va_end (ap);
326 return result;
327 #endif /* ACE_LACKS_VA_FUNCTIONS */
329 #endif /* ACE_HAS_WCHAR */
331 #if !defined ACE_FACE_DEV || !defined ACE_STDIO_USE_STDLIB_FOR_VARARGS
333 ACE_OS::printf (const char *format, ...)
335 // ACE_OS_TRACE ("ACE_OS::printf");
336 #if defined (ACE_LACKS_VA_FUNCTIONS)
337 ACE_UNUSED_ARG (format);
338 ACE_NOTSUP_RETURN (-1);
339 #else
340 va_list ap;
341 va_start (ap, format);
342 int const result = ACE_OS::vprintf (format, ap);
343 va_end (ap);
344 return result;
345 #endif /* ACE_LACKS_VA_FUNCTIONS */
347 #endif /* !ACE_FACE_DEV || !ACE_STDIO_USE_STDLIB_FOR_VARARGS */
349 #if defined (ACE_HAS_WCHAR)
351 ACE_OS::printf (const wchar_t *format, ...)
353 // ACE_OS_TRACE ("ACE_OS::printf");
354 #if defined (ACE_LACKS_VA_FUNCTIONS)
355 ACE_UNUSED_ARG (format);
356 ACE_NOTSUP_RETURN (-1);
357 #else
358 va_list ap;
359 va_start (ap, format);
360 int const result = ACE_OS::vprintf (format, ap);
361 va_end (ap);
362 return result;
363 #endif /* ACE_LACKS_VA_FUNCTIONS */
365 #endif /* ACE_HAS_WCHAR */
367 #if !defined ACE_STDIO_USE_STDLIB_FOR_VARARGS || defined ACE_LACKS_SNPRINTF
369 ACE_OS::snprintf (char *buf, size_t maxlen, const char *format, ...)
371 // ACE_OS_TRACE ("ACE_OS::snprintf");
372 #if defined (ACE_LACKS_VA_FUNCTIONS)
373 ACE_UNUSED_ARG (buf);
374 ACE_UNUSED_ARG (maxlen);
375 ACE_UNUSED_ARG (format);
376 ACE_NOTSUP_RETURN (-1);
377 #else
378 va_list ap;
379 va_start (ap, format);
380 int const result = ACE_OS::vsnprintf (buf, maxlen, format, ap);
381 va_end (ap);
382 return result;
383 #endif /* ACE_LACKS_VA_FUNCTIONS */
385 #endif /* ACE_STDIO_USE_STDLIB_FOR_VARARGS */
387 #if defined (ACE_HAS_WCHAR)
389 ACE_OS::snprintf (wchar_t *buf, size_t maxlen, const wchar_t *format, ...)
391 // ACE_OS_TRACE ("ACE_OS::snprintf");
392 #if defined (ACE_LACKS_VA_FUNCTIONS)
393 ACE_UNUSED_ARG (buf);
394 ACE_UNUSED_ARG (maxlen);
395 ACE_UNUSED_ARG (format);
396 ACE_NOTSUP_RETURN (-1);
397 #else
398 va_list ap;
399 va_start (ap, format);
400 int const result = ACE_OS::vsnprintf (buf, maxlen, format, ap);
401 va_end (ap);
402 return result;
403 #endif /* ACE_LACKS_VA_FUNCTIONS */
405 #endif /* ACE_HAS_WCHAR */
408 ACE_OS::sprintf (char *buf, const char *format, ...)
410 // ACE_OS_TRACE ("ACE_OS::sprintf");
411 #if defined (ACE_LACKS_VA_FUNCTIONS)
412 ACE_UNUSED_ARG (buf);
413 ACE_UNUSED_ARG (format);
414 ACE_NOTSUP_RETURN (-1);
415 #else
416 va_list ap;
417 va_start (ap, format);
418 int const result = ACE_OS::vsprintf (buf, format, ap);
419 va_end (ap);
420 return result;
421 #endif /* ACE_LACKS_VA_FUNCTIONS */
424 #if defined (ACE_HAS_WCHAR)
426 ACE_OS::sprintf (wchar_t *buf, const wchar_t *format, ...)
428 // ACE_OS_TRACE ("ACE_OS::sprintf");
429 #if defined (ACE_LACKS_VA_FUNCTIONS)
430 ACE_UNUSED_ARG (buf);
431 ACE_UNUSED_ARG (format);
432 ACE_NOTSUP_RETURN (-1);
433 #else
434 va_list ap;
435 va_start (ap, format);
436 int const result = ACE_OS::vsprintf (buf, format, ap);
437 va_end (ap);
438 return result;
439 #endif /* ACE_LACKS_VA_FUNCTIONS */
441 #endif /* ACE_HAS_WCHAR */
443 #if !defined (ACE_HAS_VASPRINTF) && !defined (ACE_LACKS_VA_COPY)
445 ACE_OS::vasprintf_emulation(char **bufp, const char *format, va_list argptr)
447 va_list ap;
448 va_copy (ap, argptr);
449 int size = ACE_OS::vsnprintf (0, 0, format, ap);
450 va_end (ap);
452 if (size != -1)
454 char *buf = reinterpret_cast<char*>(ACE_OS::malloc(size + 1));
455 if (!buf)
456 return -1;
458 va_list aq;
459 va_copy (aq, argptr);
460 size = ACE_OS::vsnprintf(buf, size + 1, format, aq);
461 va_end (aq);
463 if (size != -1)
464 *bufp = buf;
467 return size;
469 #endif
471 #if !defined (ACE_HAS_VASWPRINTF) && !defined (ACE_LACKS_VA_COPY)
472 #if defined (ACE_HAS_WCHAR)
474 ACE_OS::vaswprintf_emulation(wchar_t **bufp, const wchar_t *format, va_list argptr)
476 va_list ap;
477 va_copy (ap, argptr);
478 int size = ACE_OS::vsnprintf(0, 0, format, ap);
479 va_end (ap);
481 if (size != -1)
483 wchar_t *buf = reinterpret_cast<wchar_t*>
484 (ACE_OS::malloc((size + 1) * sizeof(wchar_t)));
485 if (!buf)
486 return -1;
488 va_list aq;
489 va_copy (aq, argptr);
490 size = ACE_OS::vsnprintf(buf, size + 1, format, aq);
491 va_end (aq);
493 if (size != -1)
494 *bufp = buf;
497 return size;
499 #endif /* ACE_HAS_WCHAR */
500 #endif /* !ACE_HAS_VASPRINTF */
502 #if defined (ACE_HAS_VSNPRINTF_EMULATION)
504 #ifdef ACE_LACKS_WCHAR_H
505 typedef int wint_t;
506 #elif !defined ACE_LACKS_WCHAR_STD_NAMESPACE
507 using std::wint_t;
508 # ifndef ACE_LACKS_WCSRTOMBS
509 using std::wcsrtombs;
510 # endif
511 #endif
513 namespace { // helpers for vsnprintf_emulation
514 enum Flag { SNPRINTF_NONE, SNPRINTF_GROUP, SNPRINTF_LEFT,
515 SNPRINTF_SIGN = 4, SNPRINTF_SPACE = 8, SNPRINTF_ALT = 0x10,
516 SNPRINTF_ZERO = 0x20, SNPRINTF_CHAR = 0x40, SNPRINTF_SHORT = 0x80,
517 SNPRINTF_LONG = 0x100, SNPRINTF_LONGLONG = 0x200, SNPRINTF_INTMAX = 0x400,
518 SNPRINTF_SIZET = 0x800, SNPRINTF_PTRDIFF = 0x1000,
519 SNPRINTF_LONGDOUBLE = 0x2000, SNPRINTF_UCASE = 0x4000,
520 SNPRINTF_UNSIGNED = 0x8000, SNPRINTF_NEGATIVE = 0x10000,
521 SNPRINTF_EXPONENT = 0x20000, SNPRINTF_FLEXPONENT = 0x40000,
522 SNPRINTF_HEXPONENT = 0x80000,
523 SNPRINTF_LARGE_INT = (SNPRINTF_LONG|SNPRINTF_LONGLONG|SNPRINTF_INTMAX|
524 SNPRINTF_SIZET|SNPRINTF_PTRDIFF)
527 struct Snprintf_Flags
529 Snprintf_Flags ()
530 : val_ (SNPRINTF_NONE)
533 explicit Snprintf_Flags (const char *&fmt)
534 : val_ (SNPRINTF_NONE)
536 this->parse_flags (fmt);
537 if (this->has (SNPRINTF_LEFT))
538 this->remove (SNPRINTF_ZERO);
539 if (this->has (SNPRINTF_SIGN))
540 this->remove (SNPRINTF_SPACE);
543 void parse_flags (const char *&fmt)
545 for (; true; ++fmt)
547 switch (*fmt)
549 // ' used as a flag is a POSIX extension to ISO std C
550 case '\'': this->add (SNPRINTF_GROUP); break;
551 case '-': this->add (SNPRINTF_LEFT); break;
552 case '+': this->add (SNPRINTF_SIGN); break;
553 case ' ': this->add (SNPRINTF_SPACE); break;
554 case '#': this->add (SNPRINTF_ALT); break;
555 case '0': this->add (SNPRINTF_ZERO); break;
556 default: return;
561 void parse_length (const char *&fmt)
563 if (fmt[0] == 'h' && fmt[1] == 'h')
564 this->add (SNPRINTF_CHAR), fmt += 2;
565 else if (fmt[0] == 'h')
566 this->add (SNPRINTF_SHORT), ++fmt;
567 else if (fmt[0] == 'l' && fmt[1] == 'l')
568 this->add (SNPRINTF_LONGLONG), fmt += 2;
569 else if (fmt[0] == 'l')
570 this->add (SNPRINTF_LONG), ++fmt;
571 else if (fmt[0] == 'j')
572 this->add (SNPRINTF_INTMAX), ++fmt;
573 else if (fmt[0] == 'z')
574 this->add (SNPRINTF_SIZET), ++fmt;
575 else if (fmt[0] == 't')
576 this->add (SNPRINTF_PTRDIFF), ++fmt;
577 else if (fmt[0] == 'L')
578 this->add (SNPRINTF_LONGDOUBLE), ++fmt;
581 void width (int &w)
583 if (w < 0)
585 this->add (SNPRINTF_LEFT);
586 w = -w;
590 template <typename T>
591 void value (T &v)
593 if (v < 0)
595 this->add (SNPRINTF_NEGATIVE);
596 v = -v;
600 void conv_spec (char &c)
602 if (std::isupper (c))
604 if (c == 'C' || c == 'S') // C,S specs are POSIX extensions
605 this->add (SNPRINTF_LONG);
606 else
607 this->add (SNPRINTF_UCASE);
608 c = std::tolower (c);
611 switch (c)
613 case 'o': case 'u': case 'x': this->add (SNPRINTF_UNSIGNED); break;
614 case 'p': this->add (SNPRINTF_ALT); break;
615 case 'e': this->add (SNPRINTF_EXPONENT); break;
616 case 'g': this->add (SNPRINTF_FLEXPONENT); break;
617 case 'a': this->add (SNPRINTF_HEXPONENT); break;
618 default: break;
622 void add (Flag f) { this->val_ |= f; }
623 void remove (Flag f) { this->val_ &= ~f; }
624 bool has (Flag f) const { return (this->val_ & f) == f; }
625 bool has_some (Flag f) const { return this->val_ & f; }
626 int val_;
629 struct Snprintf_Digit_Grouping
631 Snprintf_Digit_Grouping (Snprintf_Flags flags, const char *grouping,
632 char thousands)
633 : grouping_ (flags.has (SNPRINTF_GROUP) ? grouping : 0)
634 , separator_ (flags.has (SNPRINTF_GROUP) ? *grouping : CHAR_MAX)
635 , next_sep_ (this->separator_)
636 , thousands_ (thousands)
638 if (!this->separator_)
640 this->grouping_ = 0;
641 this->separator_ = this->next_sep_ = CHAR_MAX;
645 int separators_needed (int digits) const
647 if (!this->grouping_)
648 return 0;
649 const char *grouping = this->grouping_;
650 int group = *grouping;
651 int separators = 0;
652 while (group > 0 && group < CHAR_MAX && digits > group)
654 digits -= group;
655 ++separators;
656 if (grouping[1])
657 group = *++grouping;
659 return separators;
662 bool next (char *&buf)
664 const bool separate = this->next_sep_ == 0;
665 if (separate)
667 *--buf = this->thousands_;
668 if (this->grouping_[1])
669 this->separator_ = *++this->grouping_;
670 this->next_sep_ = this->separator_;
672 if (this->next_sep_ > 0 && this->next_sep_ < CHAR_MAX)
673 --this->next_sep_;
674 return separate;
677 const char *grouping_;
678 int separator_, next_sep_;
679 const char thousands_;
682 struct Snprintf_Buffer
684 Snprintf_Buffer (char *buf, size_t max)
685 : buf_ (buf)
686 , avail_ (max - 1) // last byte is not available for writes, must be null
687 , written_ (0)
690 void out (const char *s, size_t n)
692 if (n == 0)
693 return;
694 const size_t m = n > this->avail_ ? this->avail_ : n;
695 ACE_OS::memcpy (this->buf_, s, m);
696 this->buf_ += m;
697 this->avail_ -= m;
698 this->written_ += n;
701 void fill (char c, size_t n)
703 if (n == 0)
704 return;
705 const size_t m = n > this->avail_ ? this->avail_ : n;
706 ACE_OS::memset (this->buf_, c, m);
707 this->buf_ += m;
708 this->avail_ -= m;
709 this->written_ += n;
712 void pad (const char *s, size_t n, Snprintf_Flags flags, int width)
714 const int used = static_cast<int> (n);
715 if (!flags.has (SNPRINTF_LEFT) && width > used)
716 this->fill (' ', width - used);
717 this->out (s, n);
718 if (flags.has (SNPRINTF_LEFT) && width > used)
719 this->fill (' ', width - used);
722 void conv_int (ACE_UINT64 val, Snprintf_Flags flags,
723 int width, int precision, int base = 10)
725 if (val == 0 && precision == 0)
727 if (flags.has (SNPRINTF_SPACE) && !flags.has (SNPRINTF_UNSIGNED))
728 this->fill (' ', 1);
729 if (flags.has (SNPRINTF_ALT) && base == 8)
730 this->fill ('0', 1);
731 return;
734 if (precision >= 0)
735 flags.remove (SNPRINTF_ZERO);
736 if (precision == -1)
737 precision = 1;
739 #ifdef ACE_LACKS_LOCALECONV
740 static const char thousands_sep = 0;
741 static const char grouping[] = "";
742 #else
743 # ifdef localeconv
744 # undef localeconv
745 # endif
746 const std::lconv *const conv = std::localeconv ();
747 const char thousands_sep =
748 conv && *conv->thousands_sep ? *conv->thousands_sep : ',';
749 const char *grouping = conv ? conv->grouping : "";
750 #endif
752 if (base != 10)
753 flags.remove (SNPRINTF_GROUP);
754 Snprintf_Digit_Grouping dg (flags, grouping, thousands_sep);
756 char buf[100];
757 char *it = buf + sizeof buf;
758 const char a = flags.has (SNPRINTF_UCASE) ? 'A' : 'a';
759 int sep_chars = 0;
761 for (ACE_UINT64 v = val; v; v /= base)
763 if (dg.next (it))
764 ++sep_chars;
765 *--it = static_cast<char> (v % base < 10 ?
766 '0' + v % base : a + v % base - 10);
769 const int digits = static_cast<int> (buf + sizeof buf - it - sep_chars);
771 if (base == 8 && flags.has (SNPRINTF_ALT) && precision <= digits)
772 precision = digits + 1;
774 if (flags.has (SNPRINTF_NEGATIVE))
775 *--it = '-';
776 else if (flags.has (SNPRINTF_SPACE) && !flags.has (SNPRINTF_UNSIGNED))
777 *--it = ' ';
778 else if (flags.has (SNPRINTF_SIGN) && !flags.has (SNPRINTF_UNSIGNED))
779 *--it = '+';
781 const bool has_sign = it < buf + sizeof buf - digits - sep_chars;
782 bool has_0x = false;
783 if (val != 0 && base == 16 && flags.has (SNPRINTF_ALT))
785 *--it = flags.has (SNPRINTF_UCASE) ? 'X' : 'x';
786 *--it = '0';
787 has_0x = true;
790 int padding = 0;
791 if (flags.has (SNPRINTF_ZERO) || precision > digits)
793 if (precision > digits)
794 padding = precision - digits;
796 const int prefix = has_sign ? 1 : (has_0x ? 2 : 0);
797 if (flags.has (SNPRINTF_ZERO) && width > digits + sep_chars + prefix)
798 padding = width - digits - prefix - sep_chars;
800 if (!flags.has (SNPRINTF_LEFT) && digits + padding + prefix < width)
802 this->fill (' ', width - digits - padding - prefix - sep_chars);
803 width = -1;
806 this->out (it, prefix);
807 it += prefix;
808 this->fill ('0', padding);
809 padding += prefix;
812 this->pad (it, buf + sizeof buf - it, flags, width - padding);
815 void conv_float (long double val, Snprintf_Flags flags,
816 int width, int precision)
818 char buf[LDBL_MAX_10_EXP + 2];
819 char *it = buf;
821 // Find the sign bit manually, signbit() is only available with C99/C++11
822 const void *const ptr = &val;
823 const char *const pval = static_cast<const char *> (ptr);
824 #if ACE_BYTE_ORDER == ACE_LITTLE_ENDIAN
825 # if defined LDBL_MANT_DIG && LDBL_MANT_DIG == 64
826 # define SIGN_OFFSET 9
827 # else
828 # define SIGN_OFFSET (ACE_SIZEOF_LONG_DOUBLE - 1)
829 # endif
830 #else
831 # define SIGN_OFFSET 0
832 #endif
833 if (pval[SIGN_OFFSET] & 0x80)
834 val = -val, *it++ = '-';
835 else if (flags.has (SNPRINTF_SIGN))
836 *it++ = '+';
837 else if (flags.has (SNPRINTF_SPACE))
838 *it++ = ' ';
839 const bool has_sign = it > buf;
841 if (!(val >= -(std::numeric_limits<long double>::max)()
842 && val <= (std::numeric_limits<long double>::max)()))
844 if (val != val)
845 ACE_OS::strcpy (it, flags.has (SNPRINTF_UCASE) ? "NAN" : "nan");
846 else
847 ACE_OS::strcpy (it, flags.has (SNPRINTF_UCASE) ? "INF" : "inf");
848 this->conv_str (buf, flags, width, -1);
849 return;
852 #ifdef ACE_LACKS_LOCALECONV
853 static const char radix = '.', thousands_sep = 0;
854 static const char grouping[] = "";
855 #else
856 const std::lconv *const conv = std::localeconv ();
857 const char radix = conv ? *conv->decimal_point : '.';
858 const char thousands_sep =
859 conv && *conv->thousands_sep ? *conv->thousands_sep : ',';
860 const char *grouping = conv ? conv->grouping : "";
861 #endif
863 const long double log = val > 0 ? std::log10 (val) : 0;
864 int dig_left = static_cast<int> (1 + ((val >= 1) ? log : 0));
865 int exp = static_cast<int> (std::floor (log));
867 if (flags.has (SNPRINTF_FLEXPONENT))
869 const int p = precision > 0 ? precision : (precision < 0 ? 6 : 1);
870 precision = p - 1;
871 if (exp < p && exp >= -4)
872 precision -= exp;
873 else
874 flags.add (SNPRINTF_EXPONENT);
877 if (flags.has (SNPRINTF_EXPONENT))
879 dig_left = 1;
880 val /= std::pow (10.L, exp);
883 if (flags.has (SNPRINTF_HEXPONENT))
885 *it++ = '0';
886 *it++ = flags.has (SNPRINTF_UCASE) ? 'X' : 'x';
887 long double mant = std::frexp (val, &exp);
888 if (mant != 0)
889 exp -= 4;
890 const char a = flags.has (SNPRINTF_UCASE) ? 'A' : 'a';
891 *it++ = hex_digit (mant, a);
892 if (precision >= 0 || flags.has (SNPRINTF_ALT) || mant > 0)
893 *it++ = radix;
894 for (int i = 0; i < precision || precision == -1; ++i)
896 if ((precision == -1 && mant == 0) || it == buf + sizeof buf - 8)
897 break;
898 *it++ = hex_digit (mant, a);
900 flags.add (SNPRINTF_EXPONENT);
901 *it++ = flags.has (SNPRINTF_UCASE) ? 'P' : 'p';
903 else
905 #if (defined __MINGW32__ && defined __x86_64__) \
906 || (defined ACE_VXWORKS && !defined __RTP__)
907 // Avoid std::modf(long double, long double*) on MinGW-W64 64-bit:
908 // see https://sourceforge.net/p/mingw-w64/bugs/478
909 double int_part;
910 double frac_part = std::modf (static_cast<double> (val), &int_part);
911 #else
912 long double int_part;
913 long double frac_part = std::modf (val, &int_part);
914 #endif
916 Snprintf_Digit_Grouping dg (flags, grouping, thousands_sep);
917 dig_left += dg.separators_needed (dig_left);
919 for (char *dec = it + dig_left; dec > it; int_part /= 10)
921 dg.next (dec);
922 *--dec = '0' + static_cast<int> (std::fmod (int_part, 10));
925 it += dig_left;
926 const char *const frac_start = it;
928 if (precision == -1)
929 precision = 6;
930 if (precision > 0 || flags.has (SNPRINTF_ALT))
931 *it++ = radix;
933 for (int i = 0; i < precision && it < buf + sizeof buf; ++i)
935 frac_part *= 10;
936 const int digit = static_cast<int> (frac_part);
937 *it++ = '0' + digit;
938 frac_part -= digit;
941 if (flags.has (SNPRINTF_FLEXPONENT) && !flags.has (SNPRINTF_ALT))
943 for (char *f = it - 1; f >= frac_start; --f)
945 if (*f == '0' || *f == radix)
947 --it;
949 else
951 break;
957 if (flags.has (SNPRINTF_EXPONENT))
959 if (!flags.has (SNPRINTF_HEXPONENT))
960 *it++ = flags.has (SNPRINTF_UCASE) ? 'E' : 'e';
961 Snprintf_Buffer sb (it, buf + sizeof buf - it);
962 Snprintf_Flags exp_flags;
963 exp_flags.add (SNPRINTF_SIGN);
964 exp_flags.value (exp);
965 const int exp_prec = flags.has (SNPRINTF_HEXPONENT) ? 1 : 2;
966 sb.conv_int (exp, exp_flags, -1, exp_prec);
967 it = sb.buf_;
970 int used = static_cast<int> (it - buf);
971 const char *const end = it;
972 it = buf;
973 if (flags.has (SNPRINTF_ZERO) && used < width)
975 if (has_sign)
976 this->fill (*it++, 1);
977 if (flags.has (SNPRINTF_HEXPONENT))
978 this->out (it, 2), it += 2;
979 if (width > used)
980 this->fill ('0', width - used);
981 width = -1;
984 this->pad (it, end - it, flags, width);
987 static char hex_digit (long double &mant, char a)
989 mant *= 16;
990 int m = static_cast<int> (mant);
991 mant -= m;
992 return m < 10 ? '0' + m : a + m - 10;
995 void conv_char (unsigned char c, Snprintf_Flags flags, int width)
997 this->pad (reinterpret_cast<char *> (&c), 1, flags, width);
1000 void conv_str (const char *str, Snprintf_Flags flags,
1001 int width, int precision)
1003 const size_t len = ACE_OS::strlen (str),
1004 n = (precision >= 0 && precision < int (len)) ? precision : len;
1005 this->pad (str, n, flags, width);
1008 void conv_str (const wchar_t *str, Snprintf_Flags flags,
1009 int width, int precision)
1011 #ifdef ACE_LACKS_WCSRTOMBS
1012 ACE_UNUSED_ARG (str);
1013 this->conv_str ("(error: no wide string conversion)",
1014 flags, width, precision);
1015 #else
1016 std::mbstate_t mbstate = std::mbstate_t ();
1017 const size_t n = 1 + wcsrtombs (0, &str, 0, &mbstate);
1018 char *buf = static_cast<char *> (ACE_Allocator::instance ()->malloc (n));
1019 if (buf)
1021 wcsrtombs (buf, &str, n, &mbstate);
1022 this->conv_str (buf, flags, width, precision);
1024 ACE_Allocator::instance ()->free (buf);
1025 #endif
1028 char *buf_;
1029 size_t avail_, written_;
1032 #ifdef EOVERFLOW
1033 # define ACE_SNPRINTF_EOVERFLOW EOVERFLOW
1034 #else
1035 # define ACE_SNPRINTF_EOVERFLOW EINVAL
1036 #endif
1038 int snprintf_read_int (const char *&fmt)
1040 char *end = 0;
1041 const unsigned long i = ACE_OS::strtoul (fmt, &end, 10);
1042 fmt = end;
1043 if (i > INT_MAX)
1045 errno = ACE_SNPRINTF_EOVERFLOW;
1046 return -1;
1048 return static_cast<int> (i);
1051 int snprintf_positional (const char *&fmt)
1053 const char *f = fmt;
1054 const int i = snprintf_read_int (f);
1055 if (i > 0 && *f == '$')
1057 fmt = f + 1;
1058 return i;
1060 return 0;
1063 struct Snprintf_Positional_Args
1065 Snprintf_Positional_Args ()
1066 : pos_arg_ (this->pos_storage_)
1067 , scanned_ (false)
1070 ~Snprintf_Positional_Args ()
1072 if (this->pos_arg_ != this->pos_storage_)
1073 ACE_Allocator::instance ()->free (this->pos_arg_);
1076 struct Positional_Arg
1078 Positional_Arg ()
1079 : type_ (PA_UNUSED)
1082 enum {
1083 PA_UNUSED,
1084 PA_INT, PA_LONG, PA_LONGLONG, PA_INTMAX, PA_PTRDIFF, PA_SSIZE,
1085 PA_UINT, PA_ULONG, PA_ULONGLONG, PA_UINTMAX, PA_UPTRDIFF, PA_SIZE,
1086 PA_WINT, PA_DOUBLE, PA_LONGDOUBLE,
1087 PA_PCHAR, PA_PWCHAR, PA_PVOID,
1088 PA_PINT, PA_PINTMAX, PA_PLONG, PA_PLONGLONG, PA_PPTRDIFF, PA_PSHORT,
1089 PA_PSCHAR, PA_PSSIZE
1090 } type_;
1092 union
1094 int i;
1095 ACE_UINT64 ui64;
1096 ACE_INT64 i64;
1097 long double f;
1098 void *p;
1102 static void conv_storage_needed (const char *fmt, int &storage_needed)
1104 while (const char *f = ACE_OS::strpbrk (fmt, "*%"))
1106 if (!*f || *f == '%')
1107 break;
1108 const int p = snprintf_positional (++f);
1109 if (p > storage_needed)
1110 storage_needed = p;
1111 fmt = f;
1115 void scan (int n, const char *fmt, va_list ap)
1117 int storage_needed = n;
1118 const char *f = fmt;
1119 conv_storage_needed (f, storage_needed);
1120 while (const char *const pct = ACE_OS::strchr (f, '%'))
1121 if (pct[1] == '%')
1122 f = pct + 2;
1123 else
1125 const int p = snprintf_positional (++f);
1126 if (p > storage_needed)
1127 storage_needed = p;
1128 conv_storage_needed (f, storage_needed);
1131 if (size_t (storage_needed) >
1132 sizeof this->pos_storage_ / sizeof (Positional_Arg))
1133 this->pos_arg_ = static_cast<Positional_Arg *> (
1134 ACE_Allocator::instance ()->calloc (
1135 sizeof (Positional_Arg) * storage_needed));
1137 f = fmt;
1138 while (true)
1140 static const char digits[] = "0123456789";
1141 f += ACE_OS::strspn (f, "-+ #0'");
1142 if (*f == '*')
1143 (*this)[snprintf_positional (++f)].type_ = Positional_Arg::PA_INT;
1144 else
1145 f += ACE_OS::strspn (f, digits);
1147 if (f[0] == '.' && f[1] == '*')
1149 f += 2;
1150 (*this)[snprintf_positional (f)].type_ = Positional_Arg::PA_INT;
1152 else if (*f == '.')
1154 ++f;
1155 f += ACE_OS::strspn (f, digits);
1158 Snprintf_Flags flags;
1159 flags.parse_length (f);
1161 switch (*f)
1163 case 'd': case 'i':
1164 if (flags.has (SNPRINTF_LONG))
1165 (*this)[n].type_ = Positional_Arg::PA_LONG;
1166 else if (flags.has (SNPRINTF_LONGLONG))
1167 (*this)[n].type_ = Positional_Arg::PA_LONGLONG;
1168 else if (flags.has (SNPRINTF_INTMAX))
1169 (*this)[n].type_ = Positional_Arg::PA_INTMAX;
1170 else if (flags.has (SNPRINTF_SIZET))
1171 (*this)[n].type_ = Positional_Arg::PA_SSIZE;
1172 else if (flags.has (SNPRINTF_PTRDIFF))
1173 (*this)[n].type_ = Positional_Arg::PA_PTRDIFF;
1174 else
1175 (*this)[n].type_ = Positional_Arg::PA_INT;
1176 break;
1177 case 'o': case 'u': case 'x': case 'X':
1178 if (flags.has (SNPRINTF_LONG))
1179 (*this)[n].type_ = Positional_Arg::PA_ULONG;
1180 else if (flags.has (SNPRINTF_LONGLONG))
1181 (*this)[n].type_ = Positional_Arg::PA_ULONGLONG;
1182 else if (flags.has (SNPRINTF_INTMAX))
1183 (*this)[n].type_ = Positional_Arg::PA_UINTMAX;
1184 else if (flags.has (SNPRINTF_SIZET))
1185 (*this)[n].type_ = Positional_Arg::PA_SIZE;
1186 else if (flags.has (SNPRINTF_PTRDIFF))
1187 (*this)[n].type_ = Positional_Arg::PA_UPTRDIFF;
1188 else
1189 (*this)[n].type_ = Positional_Arg::PA_UINT;
1190 break;
1191 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
1192 case 'a': case 'A':
1193 (*this)[n].type_ = flags.has (SNPRINTF_LONGDOUBLE) ?
1194 Positional_Arg::PA_LONGDOUBLE : Positional_Arg::PA_DOUBLE;
1195 break;
1196 case 'c':
1197 (*this)[n].type_ = flags.has (SNPRINTF_LONG) ?
1198 Positional_Arg::PA_WINT : Positional_Arg::PA_INT;
1199 break;
1200 case 'C':
1201 (*this)[n].type_ = Positional_Arg::PA_WINT;
1202 break;
1203 case 's':
1204 (*this)[n].type_ = flags.has (SNPRINTF_LONG) ?
1205 Positional_Arg::PA_PWCHAR : Positional_Arg::PA_PCHAR;
1206 break;
1207 case 'S':
1208 (*this)[n].type_ = Positional_Arg::PA_PWCHAR;
1209 break;
1210 case 'p':
1211 (*this)[n].type_ = Positional_Arg::PA_PVOID;
1212 break;
1213 case 'n':
1214 if (flags.has (SNPRINTF_LONG))
1215 (*this)[n].type_ = Positional_Arg::PA_PLONG;
1216 else if (flags.has (SNPRINTF_LONGLONG))
1217 (*this)[n].type_ = Positional_Arg::PA_PLONGLONG;
1218 else if (flags.has (SNPRINTF_INTMAX))
1219 (*this)[n].type_ = Positional_Arg::PA_PINTMAX;
1220 else if (flags.has (SNPRINTF_SIZET))
1221 (*this)[n].type_ = Positional_Arg::PA_PSSIZE;
1222 else if (flags.has (SNPRINTF_PTRDIFF))
1223 (*this)[n].type_ = Positional_Arg::PA_PPTRDIFF;
1224 else if (flags.has (SNPRINTF_SHORT))
1225 (*this)[n].type_ = Positional_Arg::PA_PSHORT;
1226 else if (flags.has (SNPRINTF_CHAR))
1227 (*this)[n].type_ = Positional_Arg::PA_PSCHAR;
1228 else
1229 (*this)[n].type_ = Positional_Arg::PA_PINT;
1230 break;
1231 default:
1232 break;
1235 // Find the next conversion and set n to the positional arg number
1237 f = ACE_OS::strchr (f + 1, '%');
1238 while (f && f[1] == '%' && ++f);
1240 if (!f)
1241 break;
1242 n = snprintf_positional (++f);
1245 for (int i = 1; i <= storage_needed; ++i)
1246 switch ((*this)[i].type_)
1248 case Positional_Arg::PA_INT:
1249 (*this)[i].i = va_arg (ap, int);
1250 break;
1251 case Positional_Arg::PA_LONG:
1252 (*this)[i].i64 = va_arg (ap, long);
1253 break;
1254 case Positional_Arg::PA_LONGLONG:
1255 (*this)[i].i64 = va_arg (ap, long long);
1256 break;
1257 #ifndef ACE_LACKS_STDINT_H
1258 case Positional_Arg::PA_INTMAX:
1259 (*this)[i].i64 = va_arg (ap, intmax_t);
1260 break;
1261 #endif
1262 case Positional_Arg::PA_PTRDIFF:
1263 (*this)[i].i64 = va_arg (ap, ptrdiff_t);
1264 break;
1265 case Positional_Arg::PA_SSIZE:
1266 (*this)[i].i64 = va_arg (ap, ssize_t);
1267 break;
1268 case Positional_Arg::PA_UINT:
1269 (*this)[i].ui64 = va_arg (ap, unsigned int);
1270 break;
1271 case Positional_Arg::PA_ULONG:
1272 (*this)[i].ui64 = va_arg (ap, unsigned long);
1273 break;
1274 case Positional_Arg::PA_ULONGLONG:
1275 (*this)[i].ui64 = va_arg (ap, unsigned long long);
1276 break;
1277 #ifndef ACE_LACKS_STDINT_H
1278 case Positional_Arg::PA_UINTMAX:
1279 (*this)[i].ui64 = va_arg (ap, uintmax_t);
1280 break;
1281 #endif
1282 case Positional_Arg::PA_UPTRDIFF:
1283 (*this)[i].ui64 = static_cast<uintptr_t> (va_arg (ap, ptrdiff_t));
1284 break;
1285 case Positional_Arg::PA_SIZE:
1286 (*this)[i].ui64 = va_arg (ap, size_t);
1287 break;
1288 #ifdef __MINGW32__
1289 #define ACE_WINT_T_VA_ARG int
1290 #else
1291 #define ACE_WINT_T_VA_ARG wint_t
1292 #endif
1293 case Positional_Arg::PA_WINT:
1294 (*this)[i].ui64 = va_arg (ap, ACE_WINT_T_VA_ARG);
1295 break;
1296 case Positional_Arg::PA_DOUBLE:
1297 (*this)[i].f = va_arg (ap, double);
1298 break;
1299 case Positional_Arg::PA_LONGDOUBLE:
1300 (*this)[i].f = va_arg (ap, long double);
1301 break;
1302 case Positional_Arg::PA_PCHAR:
1303 (*this)[i].p = va_arg (ap, char *);
1304 break;
1305 case Positional_Arg::PA_PWCHAR:
1306 (*this)[i].p = va_arg (ap, wchar_t *);
1307 break;
1308 case Positional_Arg::PA_PVOID:
1309 (*this)[i].p = va_arg (ap, void *);
1310 break;
1311 case Positional_Arg::PA_PINT:
1312 (*this)[i].p = va_arg (ap, int *);
1313 break;
1314 #ifndef ACE_LACKS_STDINT_H
1315 case Positional_Arg::PA_PINTMAX:
1316 (*this)[i].p = va_arg (ap, intmax_t *);
1317 break;
1318 #endif
1319 case Positional_Arg::PA_PLONG:
1320 (*this)[i].p = va_arg (ap, long *);
1321 break;
1322 case Positional_Arg::PA_PLONGLONG:
1323 (*this)[i].p = va_arg (ap, long long *);
1324 break;
1325 case Positional_Arg::PA_PPTRDIFF:
1326 (*this)[i].p = va_arg (ap, ptrdiff_t *);
1327 break;
1328 case Positional_Arg::PA_PSHORT:
1329 (*this)[i].p = va_arg (ap, short *);
1330 break;
1331 case Positional_Arg::PA_PSCHAR:
1332 (*this)[i].p = va_arg (ap, signed char *);
1333 break;
1334 case Positional_Arg::PA_PSSIZE:
1335 (*this)[i].p = va_arg (ap, ssize_t *);
1336 break;
1337 default:
1338 break;
1340 this->scanned_ = true;
1343 Positional_Arg &operator[] (int idx)
1345 return this->pos_arg_[idx - 1];
1348 Positional_Arg pos_storage_[10], *pos_arg_;
1349 bool scanned_;
1351 private:
1352 Snprintf_Positional_Args (const Snprintf_Positional_Args&);
1353 Snprintf_Positional_Args& operator= (const Snprintf_Positional_Args&);
1358 ACE_OS::vsnprintf_emulation (char *buf, size_t max, const char *fmt, va_list ap)
1360 if (max > INT_MAX)
1362 errno = ACE_SNPRINTF_EOVERFLOW;
1363 return -1;
1366 Snprintf_Buffer sb (buf, max);
1367 Snprintf_Positional_Args pos_arg;
1369 while (const char *const pct = ACE_OS::strchr (fmt, '%'))
1371 // Output up to next % in format string
1372 const bool escaped = pct[1] == '%';
1373 const size_t non_conv = pct - fmt + escaped;
1374 sb.out (fmt, non_conv);
1375 fmt += 1 + non_conv;
1376 if (escaped)
1377 continue;
1379 // Check if positional args are used (%1$d)
1380 const int posn = snprintf_positional (fmt);
1381 if (posn && !pos_arg.scanned_)
1382 pos_arg.scan (posn, fmt, ap); // POSIX extension
1384 // Parse flags (+- #'0)
1385 Snprintf_Flags flags (fmt);
1387 // Parse field width (integer, *, or *n$)
1388 static const int WIDTH_PREC_UNSPEC = -1;
1389 int width = WIDTH_PREC_UNSPEC;
1390 if (*fmt == '*')
1392 ++fmt;
1393 const int width_p = snprintf_positional (fmt);
1394 width = width_p ? pos_arg[width_p].i : va_arg (ap, int);
1395 flags.width (width);
1397 else if (*fmt >= '1' && *fmt <= '9')
1399 width = snprintf_read_int (fmt);
1400 if (width == -1)
1401 return -1;
1404 // Parse precision (.integer, .*, or .*n$)
1405 int precision = WIDTH_PREC_UNSPEC;
1406 if (fmt[0] == '.' && fmt[1] == '*')
1408 fmt += 2;
1409 const int prec_p = snprintf_positional (fmt);
1410 precision = prec_p ? pos_arg[prec_p].i : va_arg (ap, int);
1411 if (precision < 0)
1412 precision = WIDTH_PREC_UNSPEC;
1414 else if (*fmt == '.')
1416 precision = snprintf_read_int (++fmt);
1417 if (precision == -1)
1418 return -1;
1421 flags.parse_length (fmt);
1423 // would be nice to have a helper function for this, but va_list
1424 // can't portably be passed to another function (even by pointer)
1425 #ifdef ACE_LACKS_STDINT_H
1426 # define GET_UNSIGNED_INTMAX
1427 #else
1428 # define GET_UNSIGNED_INTMAX \
1429 else if (flags.has (SNPRINTF_INTMAX)) \
1430 val = va_arg (ap, uintmax_t);
1431 #endif
1432 #define GET_UNSIGNED_VA \
1433 if (posn) \
1434 val = pos_arg[posn].ui64; \
1435 else if (flags.has (SNPRINTF_LONGLONG)) \
1436 val = va_arg (ap, unsigned long long); \
1437 else if (flags.has (SNPRINTF_LONG)) \
1438 val = va_arg (ap, unsigned long); \
1439 GET_UNSIGNED_INTMAX \
1440 else if (flags.has (SNPRINTF_SIZET)) \
1441 val = va_arg (ap, size_t); \
1442 else if (flags.has (SNPRINTF_PTRDIFF)) \
1443 val = static_cast<uintptr_t> (va_arg (ap, ptrdiff_t)); \
1444 else \
1445 val = va_arg (ap, unsigned int); \
1446 if (flags.has (SNPRINTF_SHORT)) \
1447 val = static_cast<unsigned short> (val); \
1448 else if (flags.has (SNPRINTF_CHAR)) \
1449 val = static_cast<unsigned char> (val)
1451 #define GET_ARG(MEMBER, TYPE) \
1452 (posn ? static_cast<TYPE> (pos_arg[posn].MEMBER) : va_arg (ap, TYPE))
1454 ACE_UINT64 val;
1455 ACE_INT64 sval;
1456 long double fval;
1457 wchar_t tmp_wstr[2] = {};
1459 // Parse conversion specifier (diouxXfFeEgGaAcCsSpn) and convert arg
1460 char spec = *fmt++;
1461 flags.conv_spec (spec);
1462 switch (spec)
1464 case 'd': case 'i':
1465 if (posn)
1466 sval = flags.has_some (SNPRINTF_LARGE_INT)
1467 ? pos_arg[posn].i64 : pos_arg[posn].i;
1468 else if (flags.has (SNPRINTF_LONGLONG))
1469 sval = va_arg (ap, long long);
1470 else if (flags.has (SNPRINTF_LONG))
1471 sval = va_arg (ap, long);
1472 #ifndef ACE_LACKS_STDINT_H
1473 else if (flags.has (SNPRINTF_INTMAX))
1474 sval = va_arg (ap, intmax_t);
1475 #endif
1476 else if (flags.has (SNPRINTF_SIZET))
1477 sval = va_arg (ap, ssize_t);
1478 else if (flags.has (SNPRINTF_PTRDIFF))
1479 sval = va_arg (ap, ptrdiff_t);
1480 else
1481 sval = va_arg (ap, int);
1483 if (flags.has (SNPRINTF_SHORT))
1484 sval = static_cast<short> (sval);
1485 else if (flags.has (SNPRINTF_CHAR))
1486 sval = static_cast<signed char> (sval);
1488 flags.value (sval);
1489 sb.conv_int (sval, flags, width, precision);
1490 break;
1492 case 'o':
1493 GET_UNSIGNED_VA;
1494 sb.conv_int (val, flags, width, precision, 8);
1495 break;
1497 case 'u':
1498 GET_UNSIGNED_VA;
1499 sb.conv_int (val, flags, width, precision);
1500 break;
1502 case 'x':
1503 GET_UNSIGNED_VA;
1504 sb.conv_int (val, flags, width, precision, 16);
1505 break;
1507 case 'f':
1508 fval = posn ? pos_arg[posn].f :
1509 (flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
1510 : va_arg (ap, double));
1511 sb.conv_float (fval, flags, width, precision);
1512 break;
1514 case 'e':
1515 fval = posn ? pos_arg[posn].f :
1516 (flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
1517 : va_arg (ap, double));
1518 sb.conv_float (fval, flags, width, precision);
1519 break;
1521 case 'g':
1522 fval = posn ? pos_arg[posn].f :
1523 (flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
1524 : va_arg (ap, double));
1525 sb.conv_float (fval, flags, width, precision);
1526 break;
1528 case 'a':
1529 fval = posn ? pos_arg[posn].f :
1530 (flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
1531 : va_arg (ap, double));
1532 sb.conv_float (fval, flags, width, precision);
1533 break;
1535 case 'c':
1536 if (flags.has (SNPRINTF_LONG))
1538 *tmp_wstr = static_cast<wchar_t> (
1539 posn ? pos_arg[posn].ui64 : va_arg (ap, ACE_WINT_T_VA_ARG));
1540 sb.conv_str (tmp_wstr, flags, width, precision);
1542 else
1543 sb.conv_char (static_cast<unsigned char> (GET_ARG (i, int)),
1544 flags, width);
1545 break;
1547 case 's':
1548 if (flags.has (SNPRINTF_LONG))
1549 sb.conv_str (GET_ARG (p, const wchar_t *), flags, width, precision);
1550 else
1551 sb.conv_str (GET_ARG (p, const char *), flags, width, precision);
1552 break;
1554 case 'p':
1555 val = reinterpret_cast<ACE_UINT64> (GET_ARG (p, void *));
1556 sb.conv_int (val, flags, width, precision, 16);
1557 break;
1559 case 'n':
1560 if (flags.has (SNPRINTF_LONGLONG))
1561 *GET_ARG (p, long long *) = sb.written_;
1562 else if (flags.has (SNPRINTF_LONG))
1563 *GET_ARG (p, long *) = static_cast<long> (sb.written_);
1564 #ifndef ACE_LACKS_STDINT_H
1565 else if (flags.has (SNPRINTF_INTMAX))
1566 *GET_ARG (p, intmax_t *) = sb.written_;
1567 #endif
1568 else if (flags.has (SNPRINTF_SIZET))
1569 *GET_ARG (p, ssize_t *) = sb.written_;
1570 else if (flags.has (SNPRINTF_PTRDIFF))
1571 *GET_ARG (p, ptrdiff_t *) = sb.written_;
1572 else if (flags.has (SNPRINTF_SHORT))
1573 *GET_ARG (p, short *) = static_cast<short> (sb.written_);
1574 else if (flags.has (SNPRINTF_CHAR))
1575 *GET_ARG (p, signed char *) =
1576 static_cast<signed char> (sb.written_);
1577 else
1578 *GET_ARG (p, int *) = static_cast<int> (sb.written_);
1579 break;
1581 default:
1582 break;
1586 // Output remaining part of format string
1587 sb.out (fmt, ACE_OS::strlen (fmt));
1588 *sb.buf_ = 0;
1589 return static_cast<int> (sb.written_);
1591 #endif // ACE_HAS_VSNPRINTF_EMULATION
1593 ACE_END_VERSIONED_NAMESPACE_DECL