Lugdunum  0.1.0
Formatter.cpp
Go to the documentation of this file.
2 #include <algorithm>
3 #include <iomanip>
4 #include <sstream>
6 
7 namespace lug {
8 namespace System {
9 namespace Logger {
10 namespace priv {
11 
12 std::string UserChars::format(Message*) const {
13  return _chars;
14 }
15 
16 void UserChars::addChar(char c) {
17  _chars += c;
18 }
19 
20 std::string LevelFlag::format(Message* message) const {
21  if (!message) {
22  return "NoMsg!";
23  }
24 
25  std::stringstream ss;
26  ss << std::left << std::setfill(' ') << std::setw(7) << message->level;
27  std::string tmp(ss.str());
28  std::transform(tmp.begin(), tmp.end(), tmp.begin(), [](char c) {
29  return static_cast<char>(toupper(c));
30  });
31  return tmp;
32 }
33 
34 std::string MessageFlag::format(Message* message) const {
35  if (!message) {
36  return "NoMsg!";
37  }
38 
39  return message->raw.str();
40 }
41 
42 } // namespace priv
43 
44 std::string Formatter::handleFlagy(const std::tm* now) {
45  std::stringstream ss;
46  ss << std::put_time(now, "%y");
47  return ss.str();
48 }
49 
50 std::string Formatter::handleFlagY(const std::tm* now) {
51  std::stringstream ss;
52  ss << std::put_time(now, "%Y");
53  return ss.str();
54 }
55 
56 std::string Formatter::handleFlagm(const std::tm* now) {
57  std::stringstream ss;
58  ss << std::put_time(now, "%m");
59  return ss.str();
60 }
61 
62 std::string Formatter::handleFlagd(const std::tm* now) {
63  std::stringstream ss;
64  ss << std::put_time(now, "%d");
65  return ss.str();
66 }
67 
68 std::string Formatter::handleFlagH(const std::tm* now) {
69  std::stringstream ss;
70  ss << std::put_time(now, "%H");
71  return ss.str();
72 }
73 
74 std::string Formatter::handleFlagM(const std::tm* now) {
75  std::stringstream ss;
76  ss << std::put_time(now, "%M");
77  return ss.str();
78 }
79 
80 std::string Formatter::handleFlagS(const std::tm* now) {
81  std::stringstream ss;
82  ss << std::put_time(now, "%S");
83  return ss.str();
84 }
85 
86 inline void Formatter::handleFlag(char flag) {
87  priv::Token token;
88 
89  switch (flag) {
90  case 'y':
91  token.basic = &Formatter::handleFlagy;
92  break;
93  case 'Y':
94  token.basic = &Formatter::handleFlagY;
95  break;
96  case 'm':
97  token.basic = &Formatter::handleFlagm;
98  break;
99  case 'd':
100  token.basic = &Formatter::handleFlagd;
101  break;
102  case 'H':
103  token.basic = &Formatter::handleFlagH;
104  break;
105  case 'M':
106  token.basic = &Formatter::handleFlagM;
107  break;
108  case 'S':
109  token.basic = &Formatter::handleFlagS;
110  break;
111  case 'v':
112  token.advanced = std::make_unique<priv::MessageFlag>();
113  break;
114  case 'l':
115  token.advanced = std::make_unique<priv::LevelFlag>();
116  break;
117  }
118 
119  _formatChain.push_back(std::move(token));
120 }
121 
122 inline void Formatter::compilePattern(const std::string& pattern) {
123  std::unique_ptr<priv::UserChars> chars;
124 
125  auto end = pattern.end();
126 
127  for (auto it = pattern.begin(); it != end; ++it) {
128  if (*it == '%') {
129  if (chars) {
130  // Append raw chars found so far
131  _formatChain.push_back(priv::Token(std::move(chars)));
132  chars = nullptr;
133  }
134 
135  if (++it != end) {
136  handleFlag(*it);
137  } else {
138  break;
139  }
140  } else {
141  // Chars not following the % sign should be displayed as is
142  if (!chars) {
143  chars = std::make_unique<priv::UserChars>();
144  }
145 
146  chars->addChar(*it);
147  }
148  }
149 
150  if (chars) {
151  // Append raw chars found so far
152  _formatChain.push_back(priv::Token(std::move(chars)));
153  }
154 }
155 
156 Formatter::Formatter(const std::string& pattern) {
157  compilePattern(pattern);
158 }
159 
160 Formatter::~Formatter() = default;
161 
162 void Formatter::format(priv::Message& msg) {
163  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
164  std::time_t tt = std::chrono::system_clock::to_time_t(now);
165  std::tm tf;
166 
167 #if defined(LUG_SYSTEM_WINDOWS)
168  // Use windows secure versions of localtime
169  localtime_s(&tf, &tt);
170 #else
171  // Use linux secure versions of localtime
172  // TODO: test on android
173  // It could not work (what is the localtime secure version for android ?)
174  localtime_r(&tt, &tf);
175 #endif
176 
177  format(msg, &tf);
178 }
179 
180 void Formatter::format(priv::Message& msg, const std::tm* now) {
181  msg.formatted.clear();
182 
183  for (priv::Token& elem : _formatChain) {
184  if (elem.basic) {
185  msg.formatted << (this->*elem.basic)(now);
186  } else if (elem.advanced) {
187  msg.formatted << elem.advanced->format(&msg);
188  }
189  }
190 }
191 
192 } // Logger
193 } // System
194 } // lug
virtual void format(priv::Message &msg)
Definition: Formatter.cpp:162
std::string handleFlagH(const std::tm *now)
Definition: Formatter.cpp:68
std::string handleFlagd(const std::tm *now)
Definition: Formatter.cpp:62
std::string handleFlagy(const std::tm *now)
Definition: Formatter.cpp:44
std::string handleFlagY(const std::tm *now)
Definition: Formatter.cpp:50
Formatter(const std::string &pattern)
Definition: Formatter.cpp:156
std::string handleFlagM(const std::tm *now)
Definition: Formatter.cpp:74
std::string handleFlagm(const std::tm *now)
Definition: Formatter.cpp:56
void compilePattern(const std::string &pattern)
Definition: Formatter.cpp:122
std::string handleFlagS(const std::tm *now)
Definition: Formatter.cpp:80