Main Page · Modules · All Classes · Class Hierarchy
MCDefs.cpp
1 /*
2  * This file is part of the AiBO+ project
3  *
4  * Copyright (C) 2005-2016 Csaba Kertész (csaba.kertesz@gmail.com)
5  *
6  * AiBO+ is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * AiBO+ is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
19  *
20  */
21 
22 #include "MCDefs.hpp"
23 
24 #include "MCLog.hpp"
25 
26 #ifndef __AIBO_BUILD__
27 #include <qdir.h>
28 #include <QtGlobal>
29 #endif
30 
31 #include <fstream>
32 
33 #if defined(__unix__) && !defined(__ANDROID__) && !defined(__AIBO_BUILD__)
34 #include <execinfo.h>
35 #endif
36 #include <unistd.h>
37 #ifdef __AIBO_BUILD__
38 #include <math.h>
39 #else
40 #include <cmath>
41 #endif
42 
43 #ifdef __AIBO_BUILD__
44 #include <MCOOP.h>
45 #endif
46 
47 #if defined(__AIBO_BUILD__)
48 extern "C"
49 {
50 jmp_buf JumpPoint;
51 int JumpPointValid = 0;
52 
53 void RaiseCppException()
54 {
55  if (JumpPointValid == 1)
56  longjmp(JumpPoint, 1);
57  else
58  abort();
59 }
60 }
61 #endif
62 
63 #ifndef __AIBO_BUILD__
64 namespace
65 {
66 static QStringList SearchPaths;
67 }
68 #endif
69 
70 boost::mt19937 MCRandomSeed::Algorithm;
71 
73 {
74  srand(seed);
75  Algorithm.seed(seed);
76 }
77 
78 
80 {
81  if (MCRand(0, 1) == 0)
82  {
83  return -1;
84  }
85  return 1;
86 }
87 
88 
89 void MCSleep(unsigned int msecs)
90 {
91 #ifdef __AIBO_BUILD__
92  Wait(msecs*1000*1000);
93 #else
94  usleep(msecs*1000);
95 #endif
96 }
97 
98 
99 #if !defined(__AIBO_BUILD__) && defined(__unix__)
100 int MCGetSystemMemorySize()
101 {
102  long pages = sysconf(_SC_PHYS_PAGES);
103  long page_size = sysconf(_SC_PAGE_SIZE);
104 
105  return (int)((float)pages / 1024*page_size / 1024);
106 }
107 #endif
108 
109 
111 {
112  return std::numeric_limits<float>::infinity();
113 }
114 
115 
117 {
118  return std::numeric_limits<double>::infinity();
119 }
120 
121 
122 bool MCIsFloatInfinity(const float value)
123 {
124 #ifdef __AIBO_BUILD__
125  return __isinff(value);
126 #else
127  return std::isinf(value);
128 #endif
129 }
130 
131 
132 bool MCIsDoubleInfinity(const double value)
133 {
134 #ifdef __AIBO_BUILD__
135  return __isinfd(value);
136 #else
137  return std::isinf(value);
138 #endif
139 }
140 
141 
142 float MCRound(float number)
143 {
144  double IntPart = 0.0;
145  float FracPart = (float)modf((double)number, &IntPart);
146 
147  if (number >= 0)
148  return (float)(FracPart >= 0.5 ? IntPart+1 : IntPart);
149 
150  return (float)(FracPart <= -0.5 ? IntPart-1 : IntPart);
151 }
152 
153 
154 float MCScaleValue(float value, float min, float max, float new_max)
155 {
156  if (MCIsFloatInfinity(value) || MCIsFloatInfinity(min) || MCIsFloatInfinity(max) ||
157  MCIsFloatInfinity(new_max) || min > max || min > new_max || value < min || value > max)
158  {
159  return value;
160  }
161  float CurrentValueRate = (value-min) / (max-min);
162 
163  return min+CurrentValueRate*(new_max-min);
164 }
165 
166 
167 int MCCompare(const std::string& item, const std::string& a, const std::string& b)
168 {
169  std::string Item = item;
170  std::string A = a;
171  std::string B = b;
172 
173  boost::algorithm::to_lower(Item);
174  boost::algorithm::to_lower(A);
175  boost::algorithm::to_lower(B);
176  int Result = 0;
177 
178  while (true)
179  {
180  if (Item.size() == 0 || (A.size() == 0 && B.size() == 0))
181  return Result;
182  if (A.size() == 0)
183  return -1;
184  if (B.size() == 0)
185  return 1;
186 
187  if (Result == 0)
188  Result = MCCompare(A[0], B[0]);
189 
190  Item.erase(0, 1);
191  A.erase(0, 1);
192  B.erase(0, 1);
193  }
194  return 0;
195 }
196 
197 
198 int MCCompare(const std::string& a, const std::string& b)
199 {
200  std::string A = a;
201  std::string B = b;
202 
203  boost::algorithm::to_lower(A);
204  boost::algorithm::to_lower(B);
205  int Result = 0;
206 
207  while (true)
208  {
209  if (A.size() == 0 && B.size() == 0)
210  return Result;
211  if (A.size() == 0)
212  return 1;
213  if (B.size() == 0)
214  return -1;
215 
216  if (Result == 0)
217  Result = MCCompare(A[0], B[0]);
218 
219  A.erase(0, 1);
220  B.erase(0, 1);
221  }
222  return 0;
223 }
224 
225 
226 bool MCFileExists(const std::string& file_name)
227 {
228  std::ifstream InputFile(file_name.c_str(), std::ios::in | std::ios::binary);
229 
230  if (!InputFile.is_open())
231  {
232  return false;
233  }
234  InputFile.close();
235  return true;
236 }
237 
238 
239 int MCGetFileSize(const std::string& file_name)
240 {
241  std::ifstream InputFile(file_name.c_str(), std::ios::in | std::ios::binary);
242 
243  if (!InputFile.is_open())
244  {
245  return -1;
246  }
247  InputFile.seekg(0, std::ifstream::end);
248  return (int)InputFile.tellg();
249 }
250 
251 
252 #ifndef __AIBO_BUILD__
253 #if defined(__unix__) && !defined(__ANDROID__)
254 namespace {
255 bool MCRealBacktraceEntry(const std::string& str)
256 {
257  if (str.length() < 5)
258  return false;
259 
260  if (str.c_str()[0] != '[' || str.c_str()[1] != '0' || str.c_str()[2] != 'x' ||
261  str.c_str()[str.length()-1] != ']')
262  {
263  return false;
264  }
265  return true;
266 }
267 }
268 
269 
270 // Nice backtrace implementation taken from: http://stackoverflow.com/questions/77005
271 void MCGenerateBacktrace()
272 {
273  void* Array[100];
274  int Size = backtrace(Array, 100);
275 
276  char **Messages = backtrace_symbols(Array, Size);
277 
278  // Skip first stack frame (points here)
279  for (int i = 1; i < Size && Messages != nullptr; ++i)
280  {
281  char* MangledName = nullptr;
282  char* OffsetBegin = nullptr;
283  char* OffsetEnd = nullptr;
284 
285  // Find parentheses and +address offset surrounding mangled name
286  for (char *Chr = Messages[i]; *Chr; ++Chr)
287  {
288  if (*Chr == '(')
289  {
290  MangledName = Chr;
291  }
292  else if (*Chr == '+')
293  {
294  OffsetBegin = Chr;
295  }
296  else if (*Chr == ')')
297  {
298  OffsetEnd = Chr;
299  break;
300  }
301  }
302 
303  // If the line could be processed, attempt to demangle the symbol
304  if (MangledName && OffsetBegin && OffsetEnd && MangledName < OffsetBegin)
305  {
306  *MangledName++ = '\0';
307  *OffsetBegin++ = '\0';
308  *OffsetEnd++ = '\0';
309 
310  int Status;
311  char *RealName = abi::__cxa_demangle(MangledName, 0, 0, &Status);
312 
313  if (Status == 0)
314  {
315  // If demangling is successful, output the demangled function name
316  MC_PRINT(MCLog::White, "[bt]: %s+%s (%s)\n", RealName, OffsetBegin, Messages[i]);
317  } else {
318  // Otherwise, output the mangled function name
319  if (strcmp("", MangledName) != 0)
320  MC_PRINT(MCLog::White, "[bt]: %s+%s (%s)\n", MangledName, OffsetBegin, Messages[i]);
321  // Return if the main() function is reached
322  if (strcmp("main", MangledName) == 0)
323  {
324  printf("\n");
325  free(Messages);
326  return;
327  }
328  }
329  free(RealName);
330  } else {
331  // Otherwise, print the whole line unless it is empty or it is just a memory address
332  if (!Messages[i] && strcmp("", Messages[i]) != 0 && MCRealBacktraceEntry(Messages[0]))
333  {
334  MC_PRINT(MCLog::White, "[bt]: %s\n", Messages[i]);
335  }
336  }
337  }
338  printf("\n");
339  free(Messages);
340 }
341 #endif
342 
343 
344 bool MCCreatePath(const QString& path)
345 {
346  if (path.isEmpty())
347  {
348  MC_WARNING("Empty path is not valid.");
349  return false;
350  }
351  // Create a directory if it does not exist.
352  QDir Path(path);
353 
354  if (!Path.exists())
355  {
356  if (!Path.mkpath(Path.absolutePath()))
357  {
358  MC_WARNING("Cannot create the directory: %s\n", qPrintable(path));
359  return false;
360  } else {
361  MC_LOG("Create directory: %s", qPrintable(path));
362  return true;
363  }
364  }
365  // Silently returns without any real work done
366  return true;
367 }
368 
369 
370 bool MCRemoveDirectory(const QString& dir_str)
371 {
372  bool Result = true;
373  QDir Dir(dir_str);
374 
375  if (Dir.exists())
376  {
377  QFileInfoList InfoList = Dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
378  QDir::AllDirs | QDir::Files, QDir::DirsFirst);
379 
380  for (int i = 0; i < InfoList.size(); ++i)
381  {
382  if (InfoList[i].isDir())
383  {
384  Result = MCRemoveDirectory(InfoList[i].absoluteFilePath());
385  } else {
386  Result = QFile::remove(InfoList[i].absoluteFilePath());
387  }
388  if (!Result)
389  {
390  return Result;
391  }
392  }
393  Result = Dir.rmdir(Dir.absolutePath());
394  }
395  return Result;
396 }
397 
398 
399 QString MCFixPath(const QString& path)
400 {
401  if (path.isEmpty())
402  {
403  MC_WARNING("Empty path is not valid.");
404  return QString();
405  }
406 #if defined(__MINGW32__) || defined(__MINGW64__)
407  return QString(path).replace('/', '\\');
408 #else
409  return QString(path).replace('\\', '/');
410 #endif
411 }
412 
413 
414 void MCAddSearchPath(const QString& path)
415 {
416  if (path.isEmpty())
417  {
418  MC_WARNING("Empty path is not valid as a search path.");
419  return;
420  }
421  SearchPaths += path;
422 }
423 
424 
425 QString MCGetDataFile(const QString& file_name)
426 {
427  if (file_name.isEmpty())
428  {
429  MC_WARNING("Empty file name is not valid.");
430  return QString();
431  }
432  QStringList Paths = SearchPaths;
433 
434  Paths += QString('.');
435  for (int i = 0; i < Paths.size(); ++i)
436  {
437  QString location;
438 
439  location = MCFixPath(Paths[i]+QDir::separator())+file_name;
440  if (QFile::exists(location))
441  {
442 // MC_LOG("Found: %s", qPrintable(location));
443  return location;
444  } else {
445 // MC_LOG("Missing: %s", qPrintable(location));
446  }
447  }
448  MC_LOG("Not found (%s)", qPrintable(file_name));
449  return QString();
450 }
451 
452 
453 QString MCGetDataSubdirectory(const QString& subdirectory)
454 {
455  if (subdirectory.isEmpty())
456  {
457  MC_WARNING("Empty directory is not valid.");
458  return QString();
459  }
460  QStringList Paths = SearchPaths;
461 
462  Paths += QString('.');
463  for (int i = 0; i < Paths.size(); ++i)
464  {
465  QString location;
466 
467  location = MCFixPath(Paths[i]+QDir::separator())+subdirectory;
468  if (QDir(location).exists())
469  {
470  MC_LOG("Found: %s", qPrintable(location));
471  return location;
472  } else {
473  MC_LOG("Missing: %s", qPrintable(location));
474  }
475  }
476  MC_LOG("Not found (%s)", qPrintable(subdirectory));
477  return QString();
478 }
479 #endif
bool MCCreatePath(const QString &path)
Create a new path if it does not exist.
Definition: MCDefs.cpp:344
int MCCompare(const std::string &item, const std::string &a, const std::string &b)
Decide whether a string is relative closer to other strings.
Definition: MCDefs.cpp:167
int MCGetFileSize(const std::string &file_name)
Get file size.
Definition: MCDefs.cpp:239
double MCDoubleInfinity()
Get double infinity.
Definition: MCDefs.cpp:116
bool MCIsDoubleInfinity(const double value)
Check a value for double infinity.
Definition: MCDefs.cpp:132
#define MC_WARNING(...)
Warning macro.
Definition: MCLog.hpp:43
T MCRand(const T &min, const T &max)
Get a random number generated with standard calls.
Definition: MCDefs.hpp:248
void MCSleep(unsigned int msecs)
Wait for some milliseconds.
Definition: MCDefs.cpp:89
QString MCGetDataFile(const QString &file_name)
Search a data file.
Definition: MCDefs.cpp:425
bool MCIsFloatInfinity(const float value)
Check a value for float infinity.
Definition: MCDefs.cpp:122
#define MC_PRINT(color,...)
Print macro with normal letters.
Definition: MCLog.hpp:49
bool MCFileExists(const std::string &file_name)
Check whether a file exists.
Definition: MCDefs.cpp:226
QString MCFixPath(const QString &path)
Fix the (back)slashes in a path according to the platform.
Definition: MCDefs.cpp:399
static boost::mt19937 Algorithm
Random number generation algorithm.
Definition: MCDefs.hpp:216
float MCRound(float number)
Round a float number.
Definition: MCDefs.cpp:142
static void SetNewSeed(int seed=(int) time(nullptr))
Set a new global random seed based on the system time.
Definition: MCDefs.cpp:72
float MCFloatInfinity()
Get float infinity.
Definition: MCDefs.cpp:110
bool MCRemoveDirectory(const QString &dir_str)
Remove a directory with its content.
Definition: MCDefs.cpp:370
float MCScaleValue(float value, float min, float max, float new_max)
Scale a value to a new range.
Definition: MCDefs.cpp:154
int MCRandSign()
Generate a random sign.
Definition: MCDefs.cpp:79
#define MC_LOG(...)
Debug macro.
Definition: MCLog.hpp:41
QString MCGetDataSubdirectory(const QString &subdirectory)
Get a data subdirectory.
Definition: MCDefs.cpp:453
void MCAddSearchPath(const QString &path)
Add a location to the search path for data files.
Definition: MCDefs.cpp:414