/src/dcmtk/oflog/libsrc/snprintf.cc
Line | Count | Source |
1 | | // Copyright (C) 2010, Vaclav Haisman. All rights reserved. |
2 | | // |
3 | | // Redistribution and use in source and binary forms, with or without modifica- |
4 | | // tion, are permitted provided that the following conditions are met: |
5 | | // |
6 | | // 1. Redistributions of source code must retain the above copyright notice, |
7 | | // this list of conditions and the following disclaimer. |
8 | | // |
9 | | // 2. Redistributions in binary form must reproduce the above copyright notice, |
10 | | // this list of conditions and the following disclaimer in the documentation |
11 | | // and/or other materials provided with the distribution. |
12 | | // |
13 | | // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, |
14 | | // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
15 | | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
16 | | // APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
17 | | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- |
18 | | // DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
19 | | // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
20 | | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
21 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
22 | | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | | |
24 | | #include "dcmtk/oflog/helpers/snprintf.h" |
25 | | #include "dcmtk/oflog/helpers/loglog.h" |
26 | | #include "dcmtk/oflog/internal/internal.h" |
27 | | #include <cstdarg> |
28 | | #include <cstdio> |
29 | | #if defined (DCMTK_OFLOG_UNICODE) |
30 | | #include <cwchar> |
31 | | #endif |
32 | | #if defined (DCMTK_LOG4CPLUS_HAVE_STDARG_H) |
33 | | # include <stdarg.h> |
34 | | #endif |
35 | | #if defined (DCMTK_LOG4CPLUS_HAVE_WCHAR_H) |
36 | | # include <wchar.h> |
37 | | #endif |
38 | | #if defined (DCMTK_LOG4CPLUS_HAVE_STDIO_H) |
39 | | # include <stdio.h> |
40 | | #endif |
41 | | |
42 | | |
43 | | namespace dcmtk { |
44 | | namespace log4cplus { namespace helpers { |
45 | | |
46 | | |
47 | | size_t const START_BUF_SIZE = 512; |
48 | | |
49 | | #if defined (DCMTK_LOG4CPLUS_USE_POOR_MANS_SNPRINTF) |
50 | | |
51 | | #if defined (_WIN32) |
52 | | char const NULL_FILE[] = "NUL"; |
53 | | #else |
54 | | char const NULL_FILE[] = "/dev/null"; |
55 | | #endif |
56 | | |
57 | | #endif |
58 | | |
59 | | namespace |
60 | | { |
61 | | |
62 | | |
63 | | #if defined (DCMTK_LOG4CPLUS_USE_POOR_MANS_SNPRINTF) |
64 | | |
65 | | static inline int vftprintf (STD_NAMESPACE FILE * file, tchar const * fmt, |
66 | | va_list args) DCMTK_LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 2, 0); |
67 | | |
68 | | static inline |
69 | | int |
70 | | vftprintf (STD_NAMESPACE FILE * file, tchar const * fmt, va_list args) |
71 | | { |
72 | | #if defined (DCMTK_OFLOG_UNICODE) |
73 | | # if defined (DCMTK_LOG4CPLUS_HAVE_VFWPRINTF_S) |
74 | | return vfwprintf_s (file, fmt, args); |
75 | | # else |
76 | | return STD_NAMESPACE vfwprintf (file, fmt, args); |
77 | | # endif |
78 | | #else |
79 | | # if defined (DCMTK_LOG4CPLUS_HAVE_VFPRINTF_S) |
80 | | return vfprintf_s (file, fmt, args); |
81 | | # else |
82 | | return STD_NAMESPACE vfprintf (file, fmt, args); |
83 | | # endif |
84 | | #endif |
85 | | } |
86 | | |
87 | | |
88 | | static inline int vstprintf (tchar * dest, size_t dest_size, |
89 | | tchar const * fmt, va_list args) |
90 | | DCMTK_LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 0); |
91 | | |
92 | | static inline |
93 | | int |
94 | | vstprintf (tchar * dest, size_t dest_size, tchar const * fmt, |
95 | | va_list args) |
96 | | { |
97 | | int ret; |
98 | | #if defined (DCMTK_OFLOG_UNICODE) |
99 | | # if defined (DCMTK_LOG4CPLUS_HAVE_VSWPRINTF_S) |
100 | | ret = vswprintf_s (dest, dest_size, fmt, args); |
101 | | # else |
102 | | ret = STD_NAMESPACE vswprintf (dest, dest_size, fmt, args); |
103 | | # endif |
104 | | #else |
105 | | # if defined (DCMTK_LOG4CPLUS_HAVE_VSPRINTF_S) |
106 | | ret = vsprintf_s (dest, dest_size, fmt, args); |
107 | | # else |
108 | | ret = STD_NAMESPACE vsprintf (dest, fmt, args); |
109 | | # endif |
110 | | #endif |
111 | | |
112 | | if (ret >= 0) |
113 | | assert (OFstatic_cast(size_t, ret) <= dest_size); |
114 | | |
115 | | return ret; |
116 | | } |
117 | | |
118 | | #else /* ?defined (DCMTK_LOG4CPLUS_USE_POOR_MANS_SNPRINTF) */ |
119 | | |
120 | | static inline int vsntprintf (tchar * dest, size_t dest_size, |
121 | | tchar const * fmt, va_list args) |
122 | | DCMTK_LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 0); |
123 | | |
124 | | static inline |
125 | | int |
126 | | vsntprintf (tchar * dest, size_t dest_size, tchar const * fmt, |
127 | | va_list args) |
128 | 0 | { |
129 | 0 | int ret; |
130 | |
|
131 | | #if defined (DCMTK_OFLOG_UNICODE) |
132 | | # if defined (DCMTK_LOG4CPLUS_HAVE__VSNWPRINTF_S) && defined (_TRUNCATE) |
133 | | ret = _vsnwprintf_s (dest, dest_size, _TRUNCATE, fmt, args); |
134 | | # else |
135 | | ret = STD_NAMESPACE vswprintf (dest, dest_size, fmt, args); |
136 | | # endif |
137 | | #else |
138 | | # if defined (DCMTK_LOG4CPLUS_HAVE_VSNPRINTF_S) && defined (_TRUNCATE) |
139 | | ret = vsnprintf_s (dest, dest_size, _TRUNCATE, fmt, args); |
140 | | # elif defined (DCMTK_LOG4CPLUS_HAVE__VSNPRINTF_S) && defined (_TRUNCATE) |
141 | | ret = _vsnprintf_s (dest, dest_size, _TRUNCATE, fmt, args); |
142 | | # elif defined (DCMTK_LOG4CPLUS_HAVE_VSNPRINTF) |
143 | | ret = vsnprintf (dest, dest_size, fmt, args); |
144 | | # elif defined (DCMTK_LOG4CPLUS_HAVE__VSNPRINTF) |
145 | | ret = _vsnprintf (dest, dest_size, fmt, args); |
146 | | # else |
147 | | # error "None of vsnprintf_s, _vsnprintf_s, vsnprintf or _vsnprintf is available." |
148 | | # endif |
149 | 0 | #endif |
150 | | |
151 | 0 | return ret; |
152 | 0 | } |
153 | | #endif |
154 | | |
155 | | |
156 | | } |
157 | | |
158 | | |
159 | | snprintf_buf::snprintf_buf () |
160 | 6 | : buf (START_BUF_SIZE) |
161 | 6 | { } |
162 | | |
163 | | |
164 | | tchar const * |
165 | | snprintf_buf::print (tchar const * fmt, ...) |
166 | 0 | { |
167 | 0 | assert (fmt); |
168 | |
|
169 | 0 | va_list args; |
170 | 0 | va_start (args, fmt); |
171 | 0 | tchar const * ret = print_va_list (fmt, args); |
172 | 0 | va_end (args); |
173 | 0 | return ret; |
174 | 0 | } |
175 | | |
176 | | |
177 | | tchar const * |
178 | | snprintf_buf::print_va_list(tchar const * fmt, va_list args) |
179 | 0 | { |
180 | 0 | int printed; |
181 | 0 | size_t const fmt_len = STD_NAMESPACE char_traits<tchar>::length (fmt); |
182 | 0 | size_t buf_size = buf.size (); |
183 | 0 | size_t const output_estimate = fmt_len + fmt_len / 2 + 1; |
184 | 0 | if (output_estimate > buf_size) |
185 | 0 | buf.resize (output_estimate); |
186 | |
|
187 | | #if defined (DCMTK_LOG4CPLUS_USE_POOR_MANS_SNPRINTF) |
188 | | STD_NAMESPACE FILE * & fnull = internal::get_ptd ()->fnull; |
189 | | if (! fnull) |
190 | | { |
191 | | fnull = STD_NAMESPACE fopen (NULL_FILE, "wb"); |
192 | | if (! fnull) |
193 | | { |
194 | | LogLog::getLogLog ()->error ( |
195 | | DCMTK_LOG4CPLUS_TEXT ("Could not open NULL_FILE.")); |
196 | | buf.clear (); |
197 | | buf.push_back (0); |
198 | | return &buf[0]; |
199 | | } |
200 | | } |
201 | | |
202 | | printed = vftprintf (fnull, fmt, args); |
203 | | if (printed == -1) |
204 | | { |
205 | | LogLog::getLogLog ()->error ( |
206 | | DCMTK_LOG4CPLUS_TEXT ("Error printing into NULL_FILE.")); |
207 | | buf.clear (); |
208 | | buf.push_back (0); |
209 | | return &buf[0]; |
210 | | } |
211 | | |
212 | | buf.resize (printed + 1); |
213 | | int sprinted = vstprintf (&buf[0], buf.size (), fmt, args); |
214 | | if (sprinted == -1) |
215 | | { |
216 | | LogLog::getLogLog ()->error ( |
217 | | DCMTK_LOG4CPLUS_TEXT ("Error printing into string.")); |
218 | | buf.clear (); |
219 | | buf.push_back (0); |
220 | | return &buf[0]; |
221 | | } |
222 | | assert (printed == sprinted); |
223 | | |
224 | | buf[sprinted] = 0; |
225 | | |
226 | | #else |
227 | 0 | do |
228 | 0 | { |
229 | 0 | printed = vsntprintf (&buf[0], buf_size - 1, fmt, args); |
230 | 0 | if (printed == -1) |
231 | 0 | { |
232 | 0 | buf_size *= 2; |
233 | 0 | buf.resize (buf_size); |
234 | 0 | } |
235 | 0 | else |
236 | 0 | buf[printed] = 0; |
237 | 0 | } |
238 | 0 | while (printed == -1); |
239 | |
|
240 | 0 | #endif |
241 | |
|
242 | 0 | return &buf[0]; |
243 | 0 | } |
244 | | |
245 | | |
246 | | } } // namespace log4cplus { namespace helpers |
247 | | } // end namespace dcmtk |