cprintf_formats.hh revision 1762
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef __CPRINTF_FORMATS_HH__
30#define __CPRINTF_FORMATS_HH__
31
32struct Format
33{
34    bool alternate_form;
35    bool flush_left;
36    bool print_sign;
37    bool blank_space;
38    bool fill_zero;
39    bool uppercase;
40    enum { dec, hex, oct } base;
41    enum { none, string, integer, character, floating } format;
42    enum { best, fixed, scientific } float_format;
43    int precision;
44    int width;
45
46    Format() { clear(); }
47
48    void clear()
49    {
50        alternate_form = false;
51        flush_left = false;
52        print_sign = false;
53        blank_space = false;
54        fill_zero = false;
55        uppercase = false;
56        base = dec;
57        format = none;
58        precision = -1;
59        width = 0;
60    }
61};
62
63template <typename T>
64inline void
65_format_char(std::ostream &out, const T &data, Format &fmt)
66{
67    using namespace std;
68
69    out << data;
70}
71
72template <typename T>
73inline void
74_format_integer(std::ostream &out, const T &data, Format &fmt)
75{
76    using namespace std;
77
78    switch (fmt.base) {
79      case Format::hex:
80        out.setf(ios::hex, ios::basefield);
81        break;
82
83      case Format::oct:
84        out.setf(ios::oct, ios::basefield);
85        break;
86
87      case Format::dec:
88        out.setf(ios::dec, ios::basefield);
89        break;
90    }
91
92    if (fmt.alternate_form) {
93        if (!fmt.fill_zero)
94            out.setf(ios::showbase);
95        else {
96            switch (fmt.base) {
97              case Format::hex:
98                out << "0x";
99                fmt.width -= 2;
100                break;
101              case Format::oct:
102                out << "0";
103                fmt.width -= 1;
104                break;
105              case Format::dec:
106                break;
107            }
108        }
109    }
110
111    if (fmt.fill_zero)
112        out.fill('0');
113
114    if (fmt.width > 0)
115        out.width(fmt.width);
116
117    if (fmt.flush_left && !fmt.fill_zero)
118        out.setf(ios::left);
119
120    if (fmt.print_sign)
121        out.setf(ios::showpos);
122
123    if (fmt.uppercase)
124        out.setf(ios::uppercase);
125
126    out << data;
127}
128
129template <typename T>
130inline void
131_format_float(std::ostream &out, const T &data, Format &fmt)
132{
133    using namespace std;
134
135    switch (fmt.float_format) {
136      case Format::scientific:
137        if (fmt.precision != -1) {
138            if (fmt.width > 0)
139                out.width(fmt.width);
140
141            if (fmt.precision == 0)
142                fmt.precision = 1;
143            else
144                out.setf(ios::scientific);
145
146            out.precision(fmt.precision);
147        } else
148            if (fmt.width > 0)
149                out.width(fmt.width);
150
151        if (fmt.uppercase)
152            out.setf(ios::uppercase);
153        break;
154
155      case Format::fixed:
156        if (fmt.precision != -1) {
157            if (fmt.width > 0)
158                out.width(fmt.width);
159
160            out.setf(ios::fixed);
161            out.precision(fmt.precision);
162        } else
163            if (fmt.width > 0)
164                out.width(fmt.width);
165
166        break;
167
168      default:
169        if (fmt.precision != -1)
170            out.precision(fmt.precision);
171
172        if (fmt.width > 0)
173            out.width(fmt.width);
174
175        break;
176    }
177
178    out << data;
179}
180
181template <typename T>
182inline void
183_format_string(std::ostream &out, const T &data, Format &fmt)
184{
185    using namespace std;
186
187#if defined(__GNUC__) && (__GNUC__ < 3) || 1
188    if (fmt.width > 0) {
189        std::stringstream foo;
190        foo << data;
191        int flen = foo.str().size();
192
193        if (fmt.width > flen) {
194            char *spaces = new char[fmt.width - flen + 1];
195            memset(spaces, ' ', fmt.width - flen);
196            spaces[fmt.width - flen] = 0;
197
198            if (fmt.flush_left)
199                out << foo.str() << spaces;
200            else
201                out << spaces << foo.str();
202
203            delete [] spaces;
204        } else
205            out << data;
206    } else
207        out << data;
208#else
209    if (fmt.width > 0)
210        out.width(fmt.width);
211    if (fmt.flush_left)
212        out.setf(ios::left);
213
214    out << data;
215#endif
216}
217
218/////////////////////////////////////////////////////////////////////////////
219//
220//  The code below controls the actual usage of formats for various types
221//
222
223//
224// character formats
225//
226template <typename T>
227inline void
228format_char(std::ostream &out, const T &data, Format &fmt)
229{ out << "<bad arg type for char format>"; }
230
231inline void
232format_char(std::ostream &out, char data, Format &fmt)
233{ _format_char(out, data, fmt); }
234
235inline void
236format_char(std::ostream &out, unsigned char data, Format &fmt)
237{ _format_char(out, data, fmt); }
238
239inline void
240format_char(std::ostream &out, signed char data, Format &fmt)
241{ _format_char(out, data, fmt); }
242
243inline void
244format_char(std::ostream &out, short data, Format &fmt)
245{ _format_char(out, (char)data, fmt); }
246
247inline void
248format_char(std::ostream &out, unsigned short data, Format &fmt)
249{ _format_char(out, (char)data, fmt); }
250
251inline void
252format_char(std::ostream &out, int data, Format &fmt)
253{ _format_char(out, (char)data, fmt); }
254
255inline void
256format_char(std::ostream &out, unsigned int data, Format &fmt)
257{ _format_char(out, (char)data, fmt); }
258
259inline void
260format_char(std::ostream &out, long data, Format &fmt)
261{ _format_char(out, (char)data, fmt); }
262
263inline void
264format_char(std::ostream &out, unsigned long data, Format &fmt)
265{ _format_char(out, (char)data, fmt); }
266
267inline void
268format_char(std::ostream &out, long long data, Format &fmt)
269{ _format_char(out, (char)data, fmt); }
270
271inline void
272format_char(std::ostream &out, unsigned long long data, Format &fmt)
273{ _format_char(out, (char)data, fmt); }
274
275//
276// integer formats
277//
278template <typename T>
279inline void
280format_integer(std::ostream &out, const T &data, Format &fmt)
281{ _format_integer(out, data, fmt); }
282inline void
283format_integer(std::ostream &out, char data, Format &fmt)
284{ _format_integer(out, data, fmt); }
285inline void
286format_integer(std::ostream &out, unsigned char data, Format &fmt)
287{ _format_integer(out, data, fmt); }
288inline void
289format_integer(std::ostream &out, signed char data, Format &fmt)
290{ _format_integer(out, data, fmt); }
291#if 0
292inline void
293format_integer(std::ostream &out, short data, Format &fmt)
294{ _format_integer(out, data, fmt); }
295inline void
296format_integer(std::ostream &out, unsigned short data, Format &fmt)
297{ _format_integer(out, data, fmt); }
298inline void
299format_integer(std::ostream &out, int data, Format &fmt)
300{ _format_integer(out, data, fmt); }
301inline void
302format_integer(std::ostream &out, unsigned int data, Format &fmt)
303{ _format_integer(out, data, fmt); }
304inline void
305format_integer(std::ostream &out, long data, Format &fmt)
306{ _format_integer(out, data, fmt); }
307inline void
308format_integer(std::ostream &out, unsigned long data, Format &fmt)
309{ _format_integer(out, data, fmt); }
310inline void
311format_integer(std::ostream &out, long long data, Format &fmt)
312{ _format_integer(out, data, fmt); }
313inline void
314format_integer(std::ostream &out, unsigned long long data, Format &fmt)
315{ _format_integer(out, data, fmt); }
316#endif
317
318//
319// floating point formats
320//
321template <typename T>
322inline void
323format_float(std::ostream &out, const T &data, Format &fmt)
324{ out << "<bad arg type for float format>"; }
325
326inline void
327format_float(std::ostream &out, float data, Format &fmt)
328{ _format_float(out, data, fmt); }
329
330inline void
331format_float(std::ostream &out, double data, Format &fmt)
332{ _format_float(out, data, fmt); }
333
334//
335// string formats
336//
337template <typename T>
338inline void
339format_string(std::ostream &out, const T &data, Format &fmt)
340{ _format_string(out, data, fmt); }
341
342inline void
343format_string(std::ostream &out, const std::stringstream &data, Format &fmt)
344{ _format_string(out, data.str(), fmt); }
345
346#endif // __CPRINTF_FORMATS_HH__
347