nsnake
Classic snake game for the terminal
Loading...
Searching...
No Matches
Utils.cpp
1// _________________________________________________________
2// | _ __ ___ _ _ _ __ |
3// | \ \ / / /\ | |_) | |\ | | | | |\ | / /`_ |
4// | \_\/\/ /_/--\ |_| \ |_| \| |_| |_| \| \_\_/ |
5// | |
6// | Adventurers, beware... |
7// | |
8// | * The following file has lots of methods accumulated |
9// | over the years. |
10// | * There isn't too much cohesion between them, so try |
11// | to understand them individually. |
12// | |
13// | |
14// | * They're mostly poor-coded, sorry 'bout that. |
15// | |
16// `---------------------------------------------------------'
17
18#include <Misc/Utils.hpp>
19
20#include <sstream> // sstream
21#include <algorithm> // find_if
22#include <ctime> // time()
23#include <unistd.h> // usleep()
24#include <sys/types.h> // opendir(), readdir()
25#include <dirent.h> // readdir()
26#include <iostream> // ofstream
27#include <fstream> // ofstream
28#include <stdlib.h> // system()
29#include <algorithm>
30#include <cstring> // strchr()
31
32// C++11 compatibility
33// I wish I could use those:
34// #include <utility>
35// #include <random>
36
37// ___ __ _ ___ ___ _
38// | |_) / /\ | |\ | | | \ / / \ | |\/|
39// |_| \ /_/--\ |_| \| |_|_/ \_\_/ |_| |
40
42{
43 // Poor choice for random numbers, I know
44 // I wish I could use C++11's random generators...
45 srand(time(NULL));
46}
47
48int Utils::Random::between(int min, int max)
49{
50 if (min > max)
51 std::swap(min, max);
52
53 return (rand() % (max - min + 1) + min);
54}
55
57{
58 // If a random number between 0 and 9 is even
59 int random_int = Utils::Random::between(0, 9);
60
61 return ((random_int % 2) == 0);
62}
63
65{
66 int x = Utils::Random::between(0, 99);
67
68 return (x < (percent * 100));
69}
70
71// _____ _ _ ____
72// | | | | | |\/| | |_
73// |_| |_| |_| | |_|__
74
75void Utils::Time::delay_ms(int delay)
76{
77 usleep((useconds_t)delay * 100);
78}
79
80// ____ _ _ ____
81// | |_ | | | | | |_
82// |_| |_| |_|__ |_|__
83
84bool Utils::File::exists(std::string path)
85{
86 return (Utils::File::size(path) != -1);
87}
88off_t Utils::File::size(std::string path)
89{
90 struct stat s;
91
92 if (stat(path.c_str(), &s) < 0)
93 return -1;
94
95 return s.st_size;
96}
97void Utils::File::mkdir_p(std::string path)
98{
99 std::string tmp(path);
100
101 if (Utils::String::back(tmp) == '/')
102 tmp[tmp.size() - 1] = '\0';
103
104 for (std::string::iterator p = tmp.begin();
105 (*p) != '\0';
106 p++)
107 {
108 if (*p == '/')
109 {
110 *p = '\0';
111 mkdir(tmp.c_str(), S_IRWXU);
112 *p = '/';
113 }
114 }
115 mkdir(tmp.c_str(), S_IRWXU);
116}
117void Utils::File::rm_rf(std::string path)
118{
119 if (! Utils::File::isDirectory(path))
120 return;
121
122 // Another BIG UGY HACK
123 //
124 // Since my program's already non-portable
125 // (POSIX systems only) and I don't have the
126 // time nor means to either use Boost or
127 // implement my own file functions, I'll
128 // have to do a big hack.
129 //
130 // It's ugly, please ignore this function.
131 //
132 // I can't believe you're still reading.
133 // Please don't continue from here.
134 //
135 // I've dishounored my family.
136 // So ashamed of myself.
137 //
138 //
139 // Next thing you know we're throwing gotos
140 // everywhere.
141 //
142 //
143 //
144 // Still reading?
145 //
146 // ...OK, I've warned you
147
148 std::string command("rm -rf " + path);
149
150 system(command.c_str());
151}
152void Utils::File::rm_f(std::string path)
153{
154 if (Utils::File::isDirectory(path))
155 return;
156
157 // This is ALSO another big hack.
158 // God-dang it
159 std::string command("rm -f " + path);
160
161 system(command.c_str());
162}
163
164bool Utils::File::create(std::string path)
165{
166 FILE* fp = fopen(path.c_str(), "w");
167 if (! fp)
168 return false;
169
170 fclose(fp);
171 return true;
172}
173void Utils::File::write(std::string path, std::string contents)
174{
175 std::ofstream file;
176 file.open(path.c_str()); // if it was C++11 we could've used std::string
177 file << contents;
178}
179bool Utils::File::isDirectory(std::string path)
180{
181 struct stat s;
182
183 if (stat(path.c_str(), &s) < 0)
184 return false;
185
186 return ((S_ISDIR(s.st_mode))?
187 true:
188 false);
189}
190bool Utils::File::isFile(std::string path)
191{
192 struct stat s;
193
194 if (stat(path.c_str(), &s) < 0)
195 return false;
196
197 return ((S_ISREG(s.st_mode))?
198 true:
199 false);
200}
201std::vector<std::string> Utils::File::ls(std::string path)
202{
203 std::vector<std::string> v;
204
205 if (! Utils::File::isDirectory(path))
206 return v;
207
208 // Opening directory
209 DIR* dir;
210
211 if (! (dir = opendir(path.c_str())))
212 return v;
213
214 // Assuring 'path' ends with '/'
215 if (Utils::String::back(path) != '/')
216 path.push_back('/');
217
218 // Getting contents
219 struct dirent* ent;
220
221 while ((ent = readdir(dir)))
222 {
223 std::string s(path + ent->d_name);
224
225 // Skipping obvious '.' and '..' dirs
226 if ((s == (path + '.')) || (s == (path + "..")))
227 continue;
228
229 v.push_back(s);
230 }
231 closedir(dir);
232
233 return v;
234}
236{
237 if (! getenv("HOME"))
238 return "";
239
240 std::string s(getenv("HOME"));
241 if (Utils::String::back(s) != '/')
242 s.push_back('/');
243
244 return s;
245}
247{
248 std::string s = Utils::File::getHome();
249 if (s.empty())
250 return "";
251
252 // Removing trailing '/'
253 Utils::String::pop_back(&s);
254
255 // Getting everything after other '/'
256 size_t pos = s.rfind('/');
257
258 if (pos == std::string::npos) // woah, wtf
259 return "";
260
261 return s.substr(pos + 1);
262}
263std::string Utils::File::basename(std::string path)
264{
265#if defined(_WIN32) && !defined(__CYGWIN__)
266 char separator = '\\';
267#else
268 char separator = '/';
269#endif
270
271 size_t position = path.rfind(separator);
272
273 // Didn't find
274 if (position == std::string::npos)
275 return path;
276
277 // Return from after the separator to the end
278 return path.substr(position + 1);
279}
280std::string Utils::File::dropBasename(std::string path)
281{
282 std::string basename = Utils::File::basename(path);
283 if (basename.empty())
284 return path;
285
286 size_t position = path.find(basename);
287
288 if (position == std::string::npos)
289 return "";
290
291 // Return from start to before the separator
292 return path.substr(0, position - 1);
293}
294std::string Utils::File::extension(std::string path)
295{
296 size_t position = path.rfind('.');
297
298 if ((position == std::string::npos) || // Didn't find
299 (position == 0)) // File name starts with a dot
300 return "";
301
302 // Return from after the dot to the end
303 return path.substr(position + 1);
304}
305std::string Utils::File::dropExtension(std::string path)
306{
307 std::string extension = Utils::File::extension(path);
308 if (extension.empty())
309 return path;
310
311 size_t position = path.find(extension);
312
313 if (position == std::string::npos)
314 return "";
315
316 // Return from start to (and including) the dot
317 return path.substr(0, position - 1);
318}
319
320// __ _____ ___ _ _ __
321// ( (` | | | |_) | | | |\ | / /`_
322// _)_) |_| |_| \ |_| |_| \| \_\_/
323
324char Utils::String::back(std::string& str)
325{
326 // Using the reverse iterator
327 return *(str.rbegin());
328}
329
330char Utils::String::front(std::string& str)
331{
332 return *(str.begin());
333}
334
335void Utils::String::pop_back(std::string* str)
336{
337 if (str->size() > 0)
338 str->resize(str->size() - 1);
339}
340
341std::string Utils::String::pop_back(std::string& str)
342{
343 return (str.substr(0, str.size() - 1));
344}
345
346const char trim_blanks[] = " \t\r\n"; // Characters to be removed
347
348std::string Utils::String::ltrim(const std::string& str)
349{
350 size_t startpos = str.find_first_not_of(trim_blanks);
351
352 // Found no blanks
353 if (startpos == std::string::npos)
354 return "";
355
356 return str.substr(startpos);
357}
358std::string Utils::String::rtrim(const std::string& str)
359{
360 size_t endpos = str.find_last_not_of(trim_blanks);
361
362 // Found no blanks
363 if (endpos == std::string::npos)
364 return "";
365
366 return str.substr(0, endpos + 1);
367}
368std::string Utils::String::trim(const std::string& str)
369{
370 return (Utils::String::ltrim(
371 Utils::String::rtrim(
372 str)));
373}
374
375std::vector<std::string> Utils::String::split(const std::string& str, char delim)
376{
377 std::stringstream ss(str); // "buffer"
378 std::string item; // current thing
379 std::vector<std::string> elems; // all things
380
381 while (std::getline(ss, item, delim))
382 elems.push_back(Utils::String::trim(item));
383
384 return elems;
385}
386
387bool Utils::String::caseInsensitiveSmallerChar(const char x, const char y)
388{
389 return (std::tolower(x) < std::tolower(y));
390}
391
392bool Utils::String::caseInsensitiveSmallerString(const std::string &a, const std::string &b)
393{
394 return std::lexicographical_compare(a.begin(), a.end(),
395 b.begin(), b.end(),
396 Utils::String::caseInsensitiveSmallerChar);
397}
398
426// All allowed characters inside the Base64 domain.
427static const std::string base64_chars =
428 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
429 "abcdefghijklmnopqrstuvwxyz"
430 "0123456789+/";
431
432// Tells if some character #c belongs to the Base64 charset.
433static inline bool isBase64(unsigned char c)
434{
435 return (isalnum(c) || (c == '+') || (c == '/'));
436}
437
438
439std::string Utils::Base64::encode(std::string str)
440{
441 // Getting the raw bytes we'll encode
442 // Dark C++ casting magic here.
443 unsigned char const* bytes_to_encode = reinterpret_cast<const unsigned char*>(str.c_str());
444 unsigned int string_size = str.size();
445
446 std::string ret;
447 int i = 0;
448 int j = 0;
449 unsigned char char_array_3[3];
450 unsigned char char_array_4[4];
451
452 while (string_size--)
453 {
454 char_array_3[i++] = *(bytes_to_encode++);
455
456 if (i == 3)
457 {
458 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
459 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
460 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
461 char_array_4[3] = char_array_3[2] & 0x3f;
462
463 for(i = 0; (i <4) ; i++)
464 ret += base64_chars[char_array_4[i]];
465 i = 0;
466 }
467 }
468
469 if (i)
470 {
471 for(j = i; j < 3; j++)
472 char_array_3[j] = '\0';
473
474 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
475 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
476 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
477 char_array_4[3] = char_array_3[2] & 0x3f;
478
479 for (j = 0; (j < i + 1); j++)
480 ret += base64_chars[char_array_4[j]];
481
482 while((i++ < 3))
483 ret += '=';
484 }
485 return ret;
486}
487
488std::string Utils::Base64::decode(std::string const& encoded_string)
489{
490 int string_size = encoded_string.size();
491 int i = 0;
492 int j = 0;
493 int in_ = 0;
494 unsigned char char_array_4[4], char_array_3[3];
495 std::string ret;
496
497 while (string_size-- && ( encoded_string[in_] != '=') && isBase64(encoded_string[in_]))
498 {
499 char_array_4[i++] = encoded_string[in_]; in_++;
500
501 if (i ==4)
502 {
503 for (i = 0; i <4; i++)
504 char_array_4[i] = base64_chars.find(char_array_4[i]);
505
506 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
507 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
508 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
509
510 for (i = 0; (i < 3); i++)
511 ret += char_array_3[i];
512 i = 0;
513 }
514 }
515
516 if (i)
517 {
518 for (j = i; j <4; j++)
519 char_array_4[j] = 0;
520
521 for (j = 0; j <4; j++)
522 char_array_4[j] = base64_chars.find(char_array_4[j]);
523
524 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
525 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
526 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
527
528 for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
529 }
530 return ret;
531}
532
533
std::string encode(std::string str)
Transforms #str into a Base64 equivalent.
Definition Utils.cpp:439
std::string decode(std::string const &s)
Transforms a Base64-encoded #str into it's regular string equivalent.
Definition Utils.cpp:488
bool isFile(std::string path)
Tells if #path is a regular file (not a directory, socket, FIFO device or whatever).
Definition Utils.cpp:190
std::string getHome()
Gets the full path of the home directory for the user running this program.
Definition Utils.cpp:235
std::string dropBasename(std::string path)
Returns the full pathname up to the last component.
Definition Utils.cpp:280
std::vector< std::string > ls(std::string path)
Lists all files withing #path.
Definition Utils.cpp:201
void rm_rf(std::string path)
Removes recursively all files within directory at #path, just like UNIX command rm -rf.
Definition Utils.cpp:117
bool create(std::string path)
Creates empty file #path.
Definition Utils.cpp:164
std::string basename(std::string path)
Returns the component of a pathname (file name and extension).
Definition Utils.cpp:263
void rm_f(std::string path)
Forcibly removes file within #path.
Definition Utils.cpp:152
std::string extension(std::string path)
Returns the extension of a file.
Definition Utils.cpp:294
void write(std::string path, std::string contents)
Writes #contents to #path.
Definition Utils.cpp:173
off_t size(std::string path)
Returns the file size of #path in bytes.
Definition Utils.cpp:88
bool exists(std::string path)
Tells if #path exists.
Definition Utils.cpp:84
std::string getUser()
Gets the user name of the person running this program.
Definition Utils.cpp:246
bool isDirectory(std::string path)
Tells if #path is a directory.
Definition Utils.cpp:179
std::string dropExtension(std::string path)
Returns the filename without it's extension.
Definition Utils.cpp:305
void mkdir_p(std::string path)
Creates #path directory hierarchy recursively, just like UNIX command mkdir -p.
Definition Utils.cpp:97
bool boolean()
Random boolean.
Definition Utils.cpp:56
bool booleanWithChance(float percent)
Random boolean with chance of #percent.
Definition Utils.cpp:64
int between(int min, int max)
Random number between min and max.
Definition Utils.cpp:48
void seed()
Must be called before any of those.
Definition Utils.cpp:41