nsnake
Classic snake game for the terminal
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 
48 int 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 
75 void Utils::Time::delay_ms(int delay)
76 {
77  usleep((useconds_t)delay * 100);
78 }
79 
80 // ____ _ _ ____
81 // | |_ | | | | | |_
82 // |_| |_| |_|__ |_|__
83 
84 bool Utils::File::exists(std::string path)
85 {
86  return (Utils::File::size(path) != -1);
87 }
88 off_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 }
97 void 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 }
117 void 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 }
152 void 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 
164 bool 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 }
173 void 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 }
179 bool 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 }
190 bool 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 }
201 std::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 }
235 std::string Utils::File::getHome()
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 }
246 std::string Utils::File::getUser()
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 }
263 std::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 }
280 std::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 }
294 std::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 }
305 std::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 
324 char Utils::String::back(std::string& str)
325 {
326  // Using the reverse iterator
327  return *(str.rbegin());
328 }
329 
330 char Utils::String::front(std::string& str)
331 {
332  return *(str.begin());
333 }
334 
335 void Utils::String::pop_back(std::string* str)
336 {
337  if (str->size() > 0)
338  str->resize(str->size() - 1);
339 }
340 
341 std::string Utils::String::pop_back(std::string& str)
342 {
343  return (str.substr(0, str.size() - 1));
344 }
345 
346 const char trim_blanks[] = " \t\r\n"; // Characters to be removed
347 
348 std::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 }
358 std::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 }
368 std::string Utils::String::trim(const std::string& str)
369 {
370  return (Utils::String::ltrim(
371  Utils::String::rtrim(
372  str)));
373 }
374 
375 std::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 
387 bool Utils::String::caseInsensitiveSmallerChar(const char x, const char y)
388 {
389  return (std::tolower(x) < std::tolower(y));
390 }
391 
392 bool 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.
427 static const std::string base64_chars =
428  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
429  "abcdefghijklmnopqrstuvwxyz"
430  "0123456789+/";
431 
432 // Tells if some character #c belongs to the Base64 charset.
433 static inline bool isBase64(unsigned char c)
434 {
435  return (isalnum(c) || (c == '+') || (c == '/'));
436 }
437 
438 
439 std::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 
488 std::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 
bool boolean()
Random boolean.
Definition: Utils.cpp:56
std::string dropBasename(std::string path)
Returns the full pathname up to the last component.
Definition: Utils.cpp:280
std::string getHome()
Gets the full path of the home directory for the user running this program.
Definition: Utils.cpp:235
std::string encode(std::string str)
Transforms #str into a Base64 equivalent.
Definition: Utils.cpp:439
off_t size(std::string path)
Returns the file size of #path in bytes.
Definition: Utils.cpp:88
void seed()
Must be called before any of those.
Definition: Utils.cpp:41
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 extension(std::string path)
Returns the extension of a file.
Definition: Utils.cpp:294
bool isDirectory(std::string path)
Tells if #path is a directory.
Definition: Utils.cpp:179
std::string decode(std::string const &s)
Transforms a Base64-encoded #str into it&#39;s regular string equivalent.
Definition: Utils.cpp:488
bool create(std::string path)
Creates empty file #path.
Definition: Utils.cpp:164
void mkdir_p(std::string path)
Creates #path directory hierarchy recursively, just like UNIX command mkdir -p.
Definition: Utils.cpp:97
std::vector< std::string > ls(std::string path)
Lists all files withing #path.
Definition: Utils.cpp:201
std::string basename(std::string path)
Returns the component of a pathname (file name and extension).
Definition: Utils.cpp:263
std::string dropExtension(std::string path)
Returns the filename without it&#39;s extension.
Definition: Utils.cpp:305
void rm_rf(std::string path)
Removes recursively all files within directory at #path, just like UNIX command rm -rf...
Definition: Utils.cpp:117
void write(std::string path, std::string contents)
Writes #contents to #path.
Definition: Utils.cpp:173
int between(int min, int max)
Random number between min and max.
Definition: Utils.cpp:48
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 booleanWithChance(float percent)
Random boolean with chance of #percent.
Definition: Utils.cpp:64
void rm_f(std::string path)
Forcibly removes file within #path.
Definition: Utils.cpp:152