Fix several corner case bugs in lexical_cast
[libs/core.git] / source / strings / fmt.cpp
1 #include "fmt.h"
2
3 using namespace std;
4
5 namespace Msp {
6
7 void Fmt::parse(const char *s)
8 {
9         const char *f = s;
10         if(*f=='%') ++f;
11
12         for(; *f; ++f)
13         {
14                 if(*f=='#')
15                 {
16                         sbase = true;
17                         spoint = true;
18                 }
19                 else if(*f=='0')
20                         fillc = '0';
21                 else if(*f=='-')
22                         align = LEFT;
23                 else if(*f=='+')
24                         spos = true;
25                 else
26                         break;
27         }
28
29         if(align==LEFT)
30                 fillc = ' ';
31
32         wd = 0;
33         for(; *f; ++f)
34         {
35                 if(*f>='0' && *f<='9')
36                         wd = wd*10+(*f-'0');
37                 else
38                         break;
39         }
40
41         if(*f=='.')
42         {
43                 ++f;
44                 prec = 0;
45                 for(; *f; ++f)
46                 {
47                         if(*f>='0' && *f<='9')
48                                 prec = prec*10+(*f-'0');
49                         else
50                                 break;
51                 }
52         }
53
54         type = NUM;
55         if(*f=='d' || *f=='u')
56                 base = DEC;
57         else if(*f=='x' || *f=='X')
58                 base = HEX;
59         else if(*f=='o')
60                 base = OCT;
61         else if(*f=='b')
62                 base = BIN;
63         else if(*f=='e' || *f=='E')
64                 fmode = SCI;
65         else if(*f=='f' || *f=='F')
66                 fmode = FIXED;
67         else if(*f=='g' || *f=='G')
68                 fmode = AUTOFLT;
69         else if(*f=='p' || *f=='P')
70         {
71                 base = HEX;
72                 sbase = true;
73         }
74         else if(*f=='c')
75                 type = CHAR;
76         else if(*f=='s')
77                 type = STR;
78         else if(*f=='i')
79                 base = AUTOBASE;
80         else
81                 throw format_error(s);
82
83         if(*f=='E' || *f=='F' || *f=='G' || *f=='X' || *f=='P')
84                 ucase = true;
85
86         ++f;
87
88         if(*f)
89                 throw format_error(s);
90 }
91
92 Fmt &Fmt::reset()
93 {
94         wd = 0;
95         prec = 6;
96         spos = false;
97         fillc = ' ';
98         base = DEC;
99         sbase = false;
100         fmode = AUTOFLT;
101         spoint = false;
102         align = RIGHT;
103         ucase = false;
104         type = STR;
105
106         return *this;
107 }
108
109 void Fmt::apply(ostream &out) const
110 {
111         out.flags(((base==HEX) ? ios_base::hex : (base==OCT) ? ios_base::oct : ios_base::dec)
112                 | ((fmode==SCI) ? ios_base::scientific : (fmode==FIXED) ? ios_base::fixed : ios_base::fmtflags(0))
113                 | (fillc=='0' ? ios_base::internal : (align==LEFT) ? ios_base::left : ios_base::right)
114                 | (sbase ? ios_base::showbase : ios_base::fmtflags(0))
115                 | (spoint ? ios_base::showpoint : ios_base::fmtflags(0))
116                 | (spos ? ios_base::showpos : ios_base::fmtflags(0))
117                 | (ucase ? ios_base::uppercase : ios_base::fmtflags(0)));
118         out.fill(fillc);
119         out.width(wd);
120         out.precision(prec);
121 }
122
123 } // namespace Msp