source: trunk/FACT++/src/tools.cc@ 18917

Last change on this file since 18917 was 18876, checked in by tbretz, 8 years ago
Added new function 'WordWrap'
File size: 8.0 KB
Line 
1// **************************************************************************
2/** @file tools.cc
3
4@todo
5 - Resolve the dependancies with dim
6 - Move code to a more appropriate place
7 - put stuff in namespaces
8*/
9// **************************************************************************
10#include "tools.h"
11
12#include <stdarg.h>
13#include <iomanip>
14#include <sstream>
15
16#include <boost/tokenizer.hpp>
17#include <boost/algorithm/string.hpp>
18
19using namespace std;
20
21string Tools::Format(const char *fmt, va_list &ap)
22{
23 int n=256;
24
25 char *ret=0;
26 while (1)
27 {
28 ret = new char[n+1];
29
30 const int sz = vsnprintf(ret, n, fmt, ap);
31 if (sz<=n)
32 break;
33
34 n *= 2;
35 delete [] ret;
36 };
37
38 string str(ret);
39
40 delete [] ret;
41
42 return str;
43}
44
45string Tools::Form(const char *fmt, ...)
46{
47 va_list ap;
48 va_start(ap, fmt);
49
50 string str = Format(fmt, ap);
51
52 va_end(ap);
53
54 return str;
55}
56
57// --------------------------------------------------------------------------
58//
59//! This is a static helper to remove leading and trailing whitespaces.
60//!
61//! @param buf
62//! a pointer to the char array from which the whitespaces should be
63//! removed
64//!
65//! @returns
66//! a std::string with the whitespaces removed from buf
67//
68string Tools::Trim(const string &str)
69{
70 // Trim Both leading and trailing spaces
71 const size_t start = str.find_first_not_of(' '); // Find the first character position after excluding leading blank spaces
72 const size_t end = str.find_last_not_of(' '); // Find the first character position from reverse af
73
74 // if all spaces or empty return an empty string
75 if (string::npos==start || string::npos==end)
76 return string();
77
78 return str.substr(start, end-start+1);
79}
80
81// --------------------------------------------------------------------------
82//
83//! This is a static helper to remove leading and trailing whitespaces and
84//! if available leading and trailing quotes, can be either ' or "
85//!
86//! @param buf
87//! a pointer to the char array to be trimmed
88//!
89//! @returns
90//! a std::string with the content trimmed
91//
92string Tools::TrimQuotes(const string &str)
93{
94 string rc = Trim(str);
95 if (rc.length()<2)
96 return rc;
97
98 const char b = rc[0];
99 const char e = rc[rc.length()-1];
100
101 if ((b=='\"' && e=='\"') || (b=='\'' && e=='\''))
102 return rc.substr(1, rc.length()-2);
103
104 return rc;
105}
106
107// --------------------------------------------------------------------------
108//
109//! This is a static helper to remove leading and trailing whitespaces.
110//!
111//! Usage example:
112//!
113//! \code
114//! string str = " Dies ist ein test fuer einen ganz langen Satz "
115//! "und ob er korrekt umgebrochen und formatiert wird. Alles "
116//! "nur ein simpler test aber trotzdem ganz wichtig.";
117//!
118//! cout << setfill('-') << setw(40) << "+" << endl;
119//! while (1)
120//! {
121//! const string rc = Tools::Wrap(str, 40);
122//! if (rc.empty())
123//! break;
124//! cout << rc << endl;
125//! }
126//! \endcode
127//!
128string Tools::Wrap(string &str, size_t width)
129{
130 const size_t pos = str.length()<width ? string::npos : str.find_last_of(' ', width);
131 if (pos==string::npos)
132 {
133 const string rc = str;
134 str = "";
135 return rc;
136 }
137
138 const size_t indent = str.find_first_not_of(' ');
139
140 const string rc = str.substr(0, pos);
141 const size_t p2 = str.find_first_not_of(' ', pos+1);
142
143 str = str.substr(0, indent) + str.substr(p2==string::npos ? pos+1 : p2);
144
145 return rc;
146}
147
148string Tools::Scientific(uint64_t val)
149{
150 ostringstream rc;
151 rc << setprecision(1) << fixed;
152
153 if (val<1000)
154 {
155 rc << val << " ";
156 return rc.str();
157 }
158
159 if (val<3000)
160 {
161 rc << val/1000. << " k";
162 return rc.str();
163 }
164
165 if (val<1000000)
166 {
167 rc << val/1000 << " k";
168 return rc.str();
169 }
170
171 if (val<3000000)
172 {
173 rc << val/1000000. << " M";
174 return rc.str();
175 }
176
177 if (val<1000000000)
178 {
179 rc << val/1000000 << " M";
180 return rc.str();
181 }
182
183 if (val<3000000000)
184 {
185 rc << val/1000000000. << " G";
186 return rc.str();
187 }
188
189 if (val<1000000000000)
190 {
191 rc << val/1000000000 << " G";
192 return rc.str();
193 }
194
195 if (val<3000000000000)
196 {
197 rc << val/1000000000000. << " T";
198 return rc.str();
199 }
200
201 if (val<1000000000000000)
202 {
203 rc << val/1000000000000 << " T";
204 return rc.str();
205 }
206
207 if (val<3000000000000000)
208 {
209 rc << val/1000000000000000. << " P";
210 return rc.str();
211 }
212
213 rc << val/1000000000000000. << " P";
214 return rc.str();
215}
216
217// --------------------------------------------------------------------------
218//
219//! Splits a string into a filename and command line arguments, like:
220//!
221//! file.txt arg1=argument1 arg2="argument 2" arg3="argument \"3\""
222//!
223//! 'file.txt' will be returned on opt, the arguments will be returned in
224//! the returned map.
225//!
226//! If the returned file name is empty, an error has occured:
227//! If the map is also empty the file name was empty, if the map has
228//! one entry then for this entry the equal sign was missing.
229//
230//! allow==true allows for positional (empty) arguments, like in
231//! file.txt arg1 arg2="argument 2" arg3
232//!
233map<string,string> Tools::Split(string &opt, bool allow)
234{
235 using namespace boost;
236 typedef escaped_list_separator<char> separator;
237
238 const string data(opt);
239
240 const tokenizer<separator> tok(data, separator("\\", " ", "\"'"));
241
242 auto it=tok.begin();
243 if (it==tok.end())
244 {
245 opt = "";
246 return map<string,string>();
247 }
248
249 opt = string(*it).find_first_of('=')==string::npos ? *it++ : "";
250
251 map<string,string> rc;
252
253 int cnt=0;
254
255 for (; it!=tok.end(); it++)
256 {
257 if (it->empty())
258 continue;
259
260 const size_t pos = it->find_first_of('=');
261 if (pos==string::npos)
262 {
263 if (allow)
264 {
265 rc[to_string(cnt++)] = *it;
266 continue;
267 }
268
269 opt = "";
270 rc.clear();
271 rc[*it] = "";
272 return rc;
273 }
274
275 rc[it->substr(0, pos)] = it->substr(pos+1);
276 }
277
278 return rc;
279}
280
281vector<string> Tools::Split(const string &str, const string &delim)
282{
283 vector<string> rc;
284 boost::split(rc, str, boost::is_any_of(delim));
285 return rc;
286}
287
288// --------------------------------------------------------------------------
289//
290//! Returns the string with a comment (introduced by a #) stripped. The
291//! comment mark can be escaped by either \# or "#"
292//!
293string Tools::Uncomment(const string &opt)
294{
295 using namespace boost;
296 typedef escaped_list_separator<char> separator;
297
298 const auto it = tokenizer<separator>(opt, separator("\\", "#", "\"'")).begin();
299
300 const int charPos = it.base() - opt.begin();
301
302 return charPos<1 ? "" : opt.substr(0, opt[charPos-1]=='#' ? charPos-1 : charPos);
303}
304
305// --------------------------------------------------------------------------
306//
307//! Wraps a given text into a vector of strings with not more than
308//! max size lines
309//!
310vector<string> Tools::WordWrap(string text, const uint16_t &max)
311{
312 if (text.size()<max)
313 return { text };
314
315 vector<string> rc;
316 while (1)
317 {
318 // Remove trailing white spaces
319 const size_t st = text.find_first_not_of(' ');
320 if (st==string::npos)
321 break;
322
323 text.erase(0, st);
324 if (text.size()<max)
325 {
326 rc.push_back(text);
327 break;
328 }
329
330 // Last white space - position to break
331 const size_t ws = text.find_last_of(' ', max);
332 if (ws==string::npos)
333 {
334 rc.push_back(text.substr(0, max));
335 text.erase(0, max);
336 continue;
337 }
338
339 // Previous non-whitespace, last position to keep
340 const size_t ch = text.find_last_not_of(' ', ws);
341 if (ch==string::npos) // found only white spaces
342 continue;
343
344 rc.push_back(text.substr(0, ch+1));
345 text.erase(0, ws);
346 }
347
348 return rc;
349}
Note: See TracBrowser for help on using the repository browser.