1 ////////////////////////////////////////////////////////////////////////////////
3 // Copyright 2006 - 2017, Paul Beckingham, Federico Hernandez.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // http://www.opensource.org/licenses/mit-license.php
25 ////////////////////////////////////////////////////////////////////////////////
38 #include <sys/select.h>
43 ////////////////////////////////////////////////////////////////////////////////
44 const std::string format (std::string& value)
49 ////////////////////////////////////////////////////////////////////////////////
50 const std::string format (const char* value)
52 std::string s (value);
56 ////////////////////////////////////////////////////////////////////////////////
57 const std::string formatHex (int value)
60 s.setf (std::ios::hex, std::ios::basefield);
65 ////////////////////////////////////////////////////////////////////////////////
66 const std::string format (float value, int width, int precision)
70 s.precision (precision);
71 if (0 < value && value < 1)
73 // For value close to zero, width - 2 (2 accounts for the first zero and
74 // the dot) is the number of digits after zero that are significant
76 for (int i = 2; i < width; i++)
78 value = roundf (value * factor) / factor;
84 ////////////////////////////////////////////////////////////////////////////////
85 const std::string format (double value, int width, int precision)
89 s.precision (precision);
90 if (0 < value && value < 1)
92 // For value close to zero, width - 2 (2 accounts for the first zero and
93 // the dot) is the number of digits after zero that are significant
95 for (int i = 2; i < width; i++)
97 value = round (value * factor) / factor;
103 ////////////////////////////////////////////////////////////////////////////////
104 const std::string format (double value)
107 s << std::fixed << value;
111 ////////////////////////////////////////////////////////////////////////////////
112 void replace_positional (
114 const std::string& from,
115 const std::string& to)
117 std::string::size_type pos = 0;
118 while ((pos = fmt.find (from, pos)) != std::string::npos)
120 fmt.replace (pos, from.length (), to);
125 ////////////////////////////////////////////////////////////////////////////////
126 std::string leftJustify (const int input, const int width)
130 std::string output = s.str ();
131 return output + std::string (width - output.length (), ' ');
134 ////////////////////////////////////////////////////////////////////////////////
135 std::string leftJustify (const std::string& input, const int width)
137 return input + std::string (width - utf8_text_width (input), ' ');
140 ////////////////////////////////////////////////////////////////////////////////
141 std::string rightJustifyZero (const int input, const int width)
144 s << std::setw (width) << std::setfill ('0') << input;
148 ////////////////////////////////////////////////////////////////////////////////
149 std::string rightJustify (const int input, const int width)
152 s << std::setw (width) << std::setfill (' ') << input;
156 ////////////////////////////////////////////////////////////////////////////////
157 std::string rightJustify (const std::string& input, const int width)
159 unsigned int len = utf8_text_width (input);
160 return (((unsigned int) width > len)
161 ? std::string (width - len, ' ')
166 ////////////////////////////////////////////////////////////////////////////////
167 std::string commify (const std::string& data)
169 // First scan for decimal point and end of digits.
170 int decimalPoint = -1;
174 for (int i = 0; i < (int) data.length (); ++i)
176 if (isdigit (data[i]))
184 if (decimalPoint != -1)
186 // In reverse order, transfer all digits up to, and including the decimal
188 for (i = (int) data.length () - 1; i >= decimalPoint; --i)
191 int consecutiveDigits = 0;
194 if (isdigit (data[i]))
198 if (++consecutiveDigits == 3 && i && isdigit (data[i - 1]))
201 consecutiveDigits = 0;
210 // In reverse order, transfer all digits up to, but not including the last
212 for (i = (int) data.length () - 1; i > end; --i)
215 int consecutiveDigits = 0;
218 if (isdigit (data[i]))
222 if (++consecutiveDigits == 3 && i && isdigit (data[i - 1]))
225 consecutiveDigits = 0;
233 // reverse result into data.
235 for (int i = (int) result.length () - 1; i >= 0; --i)
241 ////////////////////////////////////////////////////////////////////////////////
242 // Convert a quantity in bytes to a more readable format.
243 std::string formatBytes (size_t bytes)
247 if (bytes >= 995000000) sprintf (formatted, "%.1f GiB", bytes / 1000000000.0);
248 else if (bytes >= 995000) sprintf (formatted, "%.1f MiB", bytes / 1000000.0);
249 else if (bytes >= 995) sprintf (formatted, "%.1f KiB", bytes / 1000.0);
250 else sprintf (formatted, "%d B", (int)bytes);
252 return commify (formatted);
255 ////////////////////////////////////////////////////////////////////////////////
256 // Convert a quantity in seconds to a more readable format.
257 std::string formatTime (time_t seconds)
260 float days = (float) seconds / 86400.0;
262 if (seconds >= 86400 * 365) sprintf (formatted, "%.1f y", (days / 365.0));
263 else if (seconds >= 86400 * 84) sprintf (formatted, "%1d mo", (int) (days / 30));
264 else if (seconds >= 86400 * 13) sprintf (formatted, "%d wk", (int) (float) (days / 7.0));
265 else if (seconds >= 86400) sprintf (formatted, "%d d", (int) days);
266 else if (seconds >= 3600) sprintf (formatted, "%d h", (int) (seconds / 3600));
267 else if (seconds >= 60) sprintf (formatted, "%d m", (int) (seconds / 60));
268 else if (seconds >= 1) sprintf (formatted, "%d s", (int) seconds);
269 else strcpy (formatted, "-");
271 return std::string (formatted);
274 ////////////////////////////////////////////////////////////////////////////////
275 std::string printable (const std::string& input)
277 // Sanitize 'message'.
278 std::string sanitized = input;
279 std::string::size_type bad;
280 while ((bad = sanitized.find ("\r")) != std::string::npos)
281 sanitized.replace (bad, 1, "\\r");
283 while ((bad = sanitized.find ("\n")) != std::string::npos)
284 sanitized.replace (bad, 1, "\\n");
286 while ((bad = sanitized.find ("\f")) != std::string::npos)
287 sanitized.replace (bad, 1, "\\f");
289 while ((bad = sanitized.find ("\t")) != std::string::npos)
290 sanitized.replace (bad, 1, "\\t");
292 while ((bad = sanitized.find ("\v")) != std::string::npos)
293 sanitized.replace (bad, 1, "\\v");
298 ////////////////////////////////////////////////////////////////////////////////
299 std::string printable (char input)
301 // Sanitize 'message'.
302 char stringized[2] = {0};
303 stringized[0] = input;
305 std::string sanitized = stringized;
308 case '\r': sanitized = "\\r"; break;
309 case '\n': sanitized = "\\n"; break;
310 case '\f': sanitized = "\\f"; break;
311 case '\t': sanitized = "\\t"; break;
312 case '\v': sanitized = "\\v"; break;
313 default: sanitized = input; break;
319 ////////////////////////////////////////////////////////////////////////////////
320 // Iterate over the input, converting text to 'x'.
321 // Does not modify color codes.
322 std::string obfuscateText (const std::string& input)
324 std::stringstream output;
325 std::string::size_type i = 0;
329 while ((character = utf8_next_char (input, i)))
333 output << (char) character;
335 if (character == 'm')
340 if (character == 033)
343 if (inside || character == ' ')
344 output << (char) character;
350 return output.str ();
353 ////////////////////////////////////////////////////////////////////////////////