MRPT  2.0.4
os.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "system-precomp.h" // Precompiled headers
11 //
12 
13 #include <mrpt/core/exceptions.h>
14 #include <mrpt/core/format.h>
15 #include <mrpt/system/filesystem.h>
16 #include <mrpt/system/os.h>
18 
19 #ifndef HAVE_TIMEGM
20 #endif // HAVE_TIMEGM
21 
22 #include <algorithm>
23 #include <cctype>
24 #include <cfloat>
25 #include <cstdio>
26 #include <cstring>
27 #include <ctime>
28 #include <iostream>
29 #include <mutex>
30 
31 #ifdef _WIN32
32 #include <windows.h>
33 //
34 #include <conio.h>
35 #include <direct.h>
36 #include <io.h>
37 #include <sys/utime.h>
38 #include <tlhelp32.h>
39 #else
40 #include <poll.h>
41 #include <pthread.h>
42 #include <sys/select.h>
43 #include <sys/time.h>
44 #include <termios.h>
45 #include <unistd.h>
46 #include <utime.h>
47 
48 #include <cerrno>
49 #include <ctime>
50 // #include <signal.h>
51 #endif
52 
53 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
54 #include <dlfcn.h>
55 #endif
56 
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 
60 #include <map>
61 
62 #ifdef MRPT_OS_LINUX
63 #define _access access
64 #define _rmdir rmdir
65 #define _stat stat
66 #endif
67 
68 #include <sstream>
69 
70 using namespace mrpt;
71 using namespace mrpt::system;
72 using namespace std;
73 
74 #ifndef _WIN32
75 /** By ninjalj in
76  * http://stackoverflow.com/questions/3962263/checking-if-a-key-was-pressed
77  */
78 void my_aux_sighandler(int) {}
79 int myKbhit()
80 {
81  struct termios oldtio
82  {
83  }, curtio{};
84  // struct sigaction sa;
85 
86  /* Save stdin terminal attributes */
87  tcgetattr(0, &oldtio);
88 
89  // memset(&sa, 0, sizeof(struct sigaction));
90 
91  /* Set non-canonical no-echo for stdin */
92  tcgetattr(0, &curtio);
93  curtio.c_lflag &= ~(ICANON | ECHO);
94  tcsetattr(0, TCSANOW, &curtio);
95 
96  struct pollfd pfds[1];
97 
98  /* See if there is data available */
99  pfds[0].fd = 0;
100  pfds[0].events = POLLIN;
101  const int ret = poll(pfds, 1, 0);
102 
103  /* restore terminal attributes */
104  tcsetattr(0, TCSANOW, &oldtio);
105 
106  return (ret > 0);
107 }
108 
109 #endif
110 
111 /*---------------------------------------------------------------
112  timegm
113  ---------------------------------------------------------------*/
114 #ifdef HAVE_TIMEGM
115 time_t mrpt::system::os::timegm(struct tm* tm) { return ::timegm(tm); }
116 #else
117 // Version for MSVC>=2005, which lacks "timegm"
118 #ifdef HAVE_MKGMTIME
119 time_t mrpt::system::os::timegm(struct tm* tm) { return ::_mkgmtime(tm); }
120 #else
121 // generic version, slower but probably not used in any modern compiler!
122 time_t mrpt::system::os::timegm(struct tm* tm)
123 {
124  static std::mutex cs;
125  std::lock_guard<std::mutex> lock(cs);
126 
127  time_t ret;
128  char tz[256];
129 
130  /* save current timezone and set UTC */
131  char* org_tz = getenv("TZ");
132  if (org_tz) os::strcpy(tz, sizeof(tz), org_tz);
133 
134  putenv("TZ=UTC"); /* use Coordinated Universal Time (i.e. zero offset) */
135  tzset();
136 
137  ret = mktime(tm);
138  if (org_tz)
139  {
140  char buf[256];
141  mrpt::system::os::sprintf(buf, sizeof(buf), "TZ=%s", tz);
142  putenv(buf);
143  }
144  else
145  putenv("TZ=");
146  tzset();
147 
148  return ret;
149 }
150 
151 #endif
152 #endif // HAVE_TIMEGM
153 
154 /*---------------------------------------------------------------
155  mrpt::system::MRPT_getCompilationDate
156 ---------------------------------------------------------------*/
157 #include <mrpt/version.h>
158 
159 #include <cerrno>
160 #include <climits>
161 #include <cstdlib>
162 #include <ctime>
163 #include <limits>
164 
166 {
167  time_t now;
168  char* endptr;
169  const char* source_date_epoch = MRPT_SOURCE_DATE_EPOCH;
170 
171  errno = 0;
172  unsigned long epoch = strtoul(source_date_epoch, &endptr, 10);
173  if (epoch == 0 ||
174  ((errno == ERANGE &&
175  (epoch == std::numeric_limits<unsigned long>::max() || epoch == 0)) ||
176  (errno != 0 && epoch == 0)))
177  {
178  // Last resort:
179  now = time(nullptr);
180  }
181  else
182  {
183  now = epoch;
184  }
185  struct tm* build_time = gmtime(&now);
186  const int year = build_time->tm_year + 1900;
187  const int month = build_time->tm_mon + 1;
188  const int day = build_time->tm_mday;
189 
190  return mrpt::format(
191  "%i-%02i-%02i %02i:%02i:%02i UTC", year, month, day,
192  build_time->tm_hour, build_time->tm_min, build_time->tm_sec);
193 }
194 
195 /*---------------------------------------------------------------
196  mrpt::system::MRPT_getVersion
197 ---------------------------------------------------------------*/
198 string mrpt::system::MRPT_getVersion() { return string(::MRPT_version_str); }
199 /*---------------------------------------------------------------
200  sprintf
201 ---------------------------------------------------------------*/
202 int os::sprintf(
203  char* buf, [[maybe_unused]] size_t bufSize, const char* format,
204  ...) noexcept
205 {
206  int result;
207  va_list ap;
208  va_start(ap, format);
209 
210 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
211  // Use a secure version in Visual Studio 2005:
212  result = ::vsprintf_s(buf, bufSize, format, ap);
213 #else
214  // Use standard version:
215  result = ::vsprintf(buf, format, ap);
216 #endif
217 
218  va_end(ap);
219  return result;
220 }
221 
222 /*---------------------------------------------------------------
223  vsprintf
224 ---------------------------------------------------------------*/
225 int os::vsprintf(
226  char* buf, [[maybe_unused]] size_t bufSize, const char* format,
227  va_list args) noexcept
228 {
229 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
230  // Use a secure version in Visual Studio 2005:
231  return ::vsprintf_s(buf, bufSize, format, args);
232 #else
233  // Use standard version:
234  return ::vsprintf(buf, format, args);
235 #endif
236 }
237 
238 /*---------------------------------------------------------------
239  vsnprintf
240 ---------------------------------------------------------------*/
242  char* buf, size_t bufSize, const char* format, va_list args) noexcept
243 {
244 #if defined(_MSC_VER)
245 #if (_MSC_VER >= 1400)
246  // Use a secure version in Visual Studio 2005:
247  return ::vsnprintf_s(buf, bufSize, _TRUNCATE, format, args);
248 #else
249  return ::vsprintf(buf, format, args);
250 #endif
251 #else
252  // Use standard version:
253  return ::vsnprintf(buf, bufSize, format, args);
254 #endif
255 }
256 
257 /*---------------------------------------------------------------
258  fopen
259 ---------------------------------------------------------------*/
260 FILE* os::fopen(const std::string& fileName, const char* mode) noexcept
261 {
262  return fopen(fileName.c_str(), mode);
263 }
264 
265 /*---------------------------------------------------------------
266  fopen
267 ---------------------------------------------------------------*/
268 FILE* os::fopen(const char* fileName, const char* mode) noexcept
269 {
270 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
271  // Use a secure version in Visual Studio 2005:
272  FILE* f;
273  if (0 != ::fopen_s(&f, fileName, mode))
274  return NULL;
275  else
276  return f;
277 #else
278  // Use standard version:
279  return ::fopen(fileName, mode);
280 #endif
281 }
282 
283 /*---------------------------------------------------------------
284  fclose
285 ---------------------------------------------------------------*/
286 void os::fclose(FILE* f)
287 {
288  if (!f) THROW_EXCEPTION("Trying to close a nullptr 'FILE*' descriptor");
289  ::fclose(f);
290 }
291 
292 /*---------------------------------------------------------------
293  strcat
294 ---------------------------------------------------------------*/
295 char* os::strcat(
296  char* dest, [[maybe_unused]] size_t destSize, const char* source) noexcept
297 {
298 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
299  ::strcat_s(dest, destSize, source);
300 #else
301  ::strcat(dest, source);
302 #endif
303  return dest;
304 }
305 
306 /*---------------------------------------------------------------
307  strcpy
308 ---------------------------------------------------------------*/
309 char* os::strcpy(
310  char* dest, [[maybe_unused]] size_t destSize, const char* source) noexcept
311 {
312 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
313  ::strcpy_s(dest, destSize, source);
314 #else
315  ::strcpy(dest, source);
316 #endif
317  return dest;
318 }
319 
320 /*---------------------------------------------------------------
321  strcmp
322 ---------------------------------------------------------------*/
323 int os::_strcmp(const char* str1, const char* str2) noexcept
324 {
325  return ::strcmp(str1, str2);
326 }
327 
328 /*---------------------------------------------------------------
329  strcmpi
330 ---------------------------------------------------------------*/
331 int os::_strcmpi(const char* str1, const char* str2) noexcept
332 {
333 #ifdef _WIN32
334 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
335  return ::_strcmpi(str1, str2);
336 #else
337  return ::strcmpi(str1, str2);
338 #endif
339 #else
340  return ::strcasecmp(str1, str2);
341 #endif
342 }
343 
344 /** An OS-independent version of strncmp.
345  * \return It will return 0 when both strings are equal, casi sensitive.
346  */
347 int os::_strncmp(const char* str1, const char* str2, size_t count) noexcept
348 {
349  return ::strncmp(str1, str2, count);
350 }
351 
352 /** An OS-independent version of strnicmp.
353  * \return It will return 0 when both strings are equal, casi insensitive.
354  */
355 int os::_strnicmp(const char* str1, const char* str2, size_t count) noexcept
356 {
357 #if defined(_MSC_VER)
358  return ::_strnicmp(str1, str2, count);
359 #else
360  return ::strncasecmp(str1, str2, count);
361 #endif
362 }
363 
364 /*---------------------------------------------------------------
365  memcpy
366 ---------------------------------------------------------------*/
367 void os::memcpy(
368  void* dest, [[maybe_unused]] size_t destSize, const void* src,
369  size_t copyCount) noexcept
370 {
371 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
372  ::memcpy_s(dest, destSize, src, copyCount);
373 #else
374  ::memcpy(dest, src, copyCount);
375 #endif
376 }
377 
378 /*---------------------------------------------------------------
379  getch
380 ---------------------------------------------------------------*/
381 int os::getch() noexcept
382 {
383 #ifdef _WIN32
384  return ::getch(); // cin.get();
385 #else
386  struct termios oldt
387  {
388  }, newt{};
389  int ch;
390  tcgetattr(STDIN_FILENO, &oldt);
391  newt = oldt;
392  newt.c_lflag &= ~(ICANON | ECHO);
393  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
394  ch = getchar();
395  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
396  return ch;
397 #endif
398 }
399 
400 /*---------------------------------------------------------------
401  kbhit
402 ---------------------------------------------------------------*/
403 bool os::kbhit() noexcept
404 {
405 #ifdef _WIN32
406 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
407  return ::_kbhit() != 0;
408 #else
409  return ::kbhit() != 0;
410 #endif
411 #else
412  return myKbhit();
413 #endif
414 }
415 
416 /*---------------------------------------------------------------
417  os::fprintf
418 ---------------------------------------------------------------*/
419 int os::fprintf(FILE* fil, const char* frm, ...) noexcept
420 {
421  int result;
422  va_list ap;
423  va_start(ap, frm);
424 
425 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
426  // Use a secure version in Visual Studio 2005:
427  result = ::vfprintf_s(fil, frm, ap);
428 
429 #else
430  // Use standard version:
431  result = ::vfprintf(fil, frm, ap);
432 #endif
433 
434  va_end(ap);
435  return result;
436 }
437 
438 /*---------------------------------------------------------------
439  mrpt::system::pause
440 ---------------------------------------------------------------*/
441 void mrpt::system::pause(const std::string& msg) noexcept
442 {
443  std::cout << msg << std::endl;
444  os::getch();
445 }
446 
447 /*---------------------------------------------------------------
448  clearConsole
449 ---------------------------------------------------------------*/
451 {
452 #ifdef _WIN32
453  int ret = ::system("cls");
454 #else
455  int ret = ::system("clear");
456 #endif
457  if (ret)
458  cerr << "[mrpt::system::clearConsole] Error invoking 'clear screen' "
459  << endl;
460 }
461 
462 /*---------------------------------------------------------------
463  _strtoll
464  ---------------------------------------------------------------*/
465 int64_t mrpt::system::os::_strtoll(const char* nptr, char** endptr, int base)
466 {
467 #ifdef _WIN32
468  return (int64_t)::strtol(nptr, endptr, base);
469 #else
470  return (int64_t)::strtoll(nptr, endptr, base);
471 #endif
472 }
473 
474 /*---------------------------------------------------------------
475  _strtoull
476  ---------------------------------------------------------------*/
477 uint64_t mrpt::system::os::_strtoull(const char* nptr, char** endptr, int base)
478 {
479 #ifdef _WIN32
480  return (uint64_t)::strtoul(nptr, endptr, base);
481 #else
482  return (uint64_t)::strtoull(nptr, endptr, base);
483 #endif
484 }
485 
486 void mrpt::system::setConsoleColor(TConsoleColor color, bool changeStdErr)
487 {
488  static const int TS_NORMAL = 0;
489  static const int TS_BLUE = 1;
490  static const int TS_GREEN = 2;
491  static const int TS_RED = 4;
492 #ifdef _WIN32
493  static int normal_attributes = -1;
494  HANDLE hstdout =
495  GetStdHandle(changeStdErr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
496  fflush(changeStdErr ? stderr : stdout);
497 
498  if (normal_attributes < 0)
499  {
500  CONSOLE_SCREEN_BUFFER_INFO info;
501  GetConsoleScreenBufferInfo(hstdout, &info);
502  normal_attributes = info.wAttributes;
503  }
504 
505  SetConsoleTextAttribute(
506  hstdout,
507  (WORD)(
508  color == TS_NORMAL ? normal_attributes
509  : ((color & TS_BLUE ? FOREGROUND_BLUE : 0) |
510  (color & TS_GREEN ? FOREGROUND_GREEN : 0) |
511  (color & TS_RED ? FOREGROUND_RED : 0) |
512  FOREGROUND_INTENSITY)));
513 #else
514  // *nix:
515  FILE* f = changeStdErr ? stdout : stderr;
516  const int fd = changeStdErr ? STDOUT_FILENO : STDERR_FILENO;
517 
518  // No color support if it is not a real console:
519  if (!isatty(fd)) return;
520 
521  static TConsoleColor last_color = mrpt::system::CONCOL_NORMAL;
522  if (color == last_color) return;
523  last_color = color;
524 
525  static const uint8_t ansi_tab[] = {30, 34, 32, 36, 31, 35, 33, 37};
526  int code = 0;
527  fflush(f);
528  if (color != TS_NORMAL)
529  code = ansi_tab[color & (TS_BLUE | TS_GREEN | TS_RED)];
530  fprintf(f, "\x1b[%dm", code);
531 #endif
532 }
533 
534 const char* sLicenseTextF =
535  " Mobile Robot Programming Toolkit (MRPT) "
536  " \n"
537  " https://www.mrpt.org/ "
538  " "
539  " \n"
540  " "
541  " \n"
542  " Copyright (c) 2005-%Y, Individual contributors, see AUTHORS file "
543  "\n"
544  " See: https://www.mrpt.org/Authors - All rights reserved. "
545  " "
546  " \n"
547  " Released under BSD License. See details in https://www.mrpt.org/License "
548  " "
549  " \n";
550 
551 const std::string& mrpt::system::getMRPTLicense()
552 {
553  static bool sLicenseTextReady = false;
554  static std::string sLicenseText;
555 
556  if (!sLicenseTextReady)
557  {
558  // Automatically update the last year of the copyright to the
559  // compilation date:
560  time_t rawtime;
561  struct tm* timeinfo;
562  time(&rawtime);
563  timeinfo = localtime(&rawtime);
564 
565  char buf[1024];
566  ::strftime(buf, sizeof(buf), sLicenseTextF, timeinfo);
567  sLicenseText = std::string(buf);
568  sLicenseTextReady = true;
569  }
570  return sLicenseText;
571 }
572 
573 #ifdef _WIN32
574 std::string winerror2str(const char* errorPlaceName)
575 {
576  char str[700];
577  DWORD e = GetLastError();
578  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, e, 0, str, sizeof(str), NULL);
579  std::string s;
580  s = "[";
581  s += errorPlaceName;
582  s += "] Error: ";
583  s += str;
584  return s;
585 }
586 #endif
587 
588 /*---------------------------------------------------------------
589 launchProcess
590 ---------------------------------------------------------------*/
591 bool mrpt::system::launchProcess(const std::string& command)
592 {
593 #ifdef _WIN32
594  STARTUPINFOA SI;
595  PROCESS_INFORMATION PI;
596  memset(&SI, 0, sizeof(STARTUPINFOA));
597  SI.cb = sizeof(STARTUPINFOA);
598  if (CreateProcessA(
599  NULL, (LPSTR)command.c_str(), NULL, NULL, true, 0, NULL, NULL, &SI,
600  &PI))
601  {
602  // Wait:
603  WaitForSingleObject(PI.hProcess, INFINITE);
604  return true;
605  } // End of process executed OK
606  else
607  {
608  std::cerr << winerror2str("launchProcess");
609  return false;
610  }
611 
612 #else
613 
614  return 0 == ::system(command.c_str());
615 
616 #endif
617 
618 } // end launchProcess
619 
620 #include <mrpt/mrpt_paths_config.h>
622 {
623  static bool mrpt_shared_first_call = true;
624  static std::string found_mrpt_shared_dir;
625 
626  if (mrpt_shared_first_call)
627  {
628  mrpt_shared_first_call = false;
629 
630  for (int attempt = 0;; attempt++)
631  {
632  std::string dir;
633  switch (attempt)
634  {
635  case 0:
636  dir = string(MRPT_SOURCE_BASE_DIRECTORY) +
637  string("/share/mrpt/");
638  break;
639  case 1:
640  dir = string(MRPT_INSTALL_PREFIX_DIRECTORY) +
641  string("/share/mrpt/");
642  break;
643 #ifdef _WIN32
644  case 2:
645  {
646  char curExe[4096];
647  GetModuleFileNameA(nullptr, curExe, sizeof(curExe));
648 
650  std::string(curExe)) +
651  "/../share/mrpt/";
652  }
653  break;
654 #endif
655 
656  default:
657  found_mrpt_shared_dir = ".";
658  break;
659  };
660  if (!dir.empty() && mrpt::system::directoryExists(dir))
661  found_mrpt_shared_dir = dir;
662 
663  if (!found_mrpt_shared_dir.empty()) break;
664  }
665  }
666 
667  return found_mrpt_shared_dir;
668 } // end of find_mrpt_shared_dir
669 
671  const std::string& command, std::string* output /*=NULL*/,
672  const std::string& mode /*="r"*/)
673 {
674  using namespace std;
675 
676  // Create the stringstream
677  stringstream sout;
678  int exit_code = -1;
679 
680 #ifndef _WIN32
681  // Run Popen
682  FILE* in;
683  char buff[512];
684 
685  // Test output
686  if (!(in = popen(command.c_str(), mode.c_str())))
687  {
688  sout << "Popen Execution failed!" << endl;
689  *output = sout.str();
690 
691  return -1;
692  }
693 
694  // Parse output
695  while (fgets(buff, sizeof(buff), in) != nullptr)
696  {
697  sout << buff;
698  }
699 
700  // Close
701  exit_code = pclose(in);
702 #else
703  try
704  {
705  exit_code = -1;
706 
707  HANDLE g_hChildStd_IN_Rd = NULL;
708  HANDLE g_hChildStd_IN_Wr = NULL;
709  HANDLE g_hChildStd_OUT_Rd = NULL;
710  HANDLE g_hChildStd_OUT_Wr = NULL;
711 
712  HANDLE g_hInputFile = NULL;
713  SECURITY_ATTRIBUTES saAttr;
714  // Set the bInheritHandle flag so pipe handles are inherited.
715  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
716  saAttr.bInheritHandle = TRUE;
717  saAttr.lpSecurityDescriptor = NULL;
718  // Create a pipe for the child process's STDOUT.
719  if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
720  throw winerror2str("StdoutRd CreatePipe");
721 
722  // Ensure the read handle to the pipe for STDOUT is not inherited.
723 
724  if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
725  throw winerror2str("Stdout SetHandleInformation");
726 
727  // Create a pipe for the child process's STDIN.
728 
729  if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
730  throw winerror2str("Stdin CreatePipe");
731 
732  // Ensure the write handle to the pipe for STDIN is not inherited.
733 
734  if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
735  throw winerror2str("Stdin SetHandleInformation");
736 
737  // Create the child process:
738  PROCESS_INFORMATION piProcInfo;
739  STARTUPINFOA siStartInfo;
740  BOOL bSuccess = FALSE;
741 
742  // Set up members of the PROCESS_INFORMATION structure.
743 
744  ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
745 
746  // Set up members of the STARTUPINFO structure.
747  // This structure specifies the STDIN and STDOUT handles for
748  // redirection.
749 
750  ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
751  siStartInfo.cb = sizeof(STARTUPINFO);
752  siStartInfo.hStdError = g_hChildStd_OUT_Wr;
753  siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
754  siStartInfo.hStdInput = g_hChildStd_IN_Rd;
755  siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
756 
757  // Create the child process.
758  bSuccess = CreateProcessA(
759  NULL,
760  (LPSTR)command.c_str(), // command line
761  NULL, // process security attributes
762  NULL, // primary thread security attributes
763  TRUE, // handles are inherited
764  0, // creation flags
765  NULL, // use parent's environment
766  NULL, // use parent's current directory
767  &siStartInfo, // STARTUPINFO pointer
768  &piProcInfo); // receives PROCESS_INFORMATION
769 
770  // If an error occurs, exit the application.
771  if (!bSuccess) throw winerror2str("CreateProcess");
772 
773  // Read from pipe that is the standard output for child process.
774  DWORD dwRead;
775  CHAR chBuf[4096];
776  bSuccess = FALSE;
777  DWORD exitval = 0;
778  exit_code = 0;
779  for (;;)
780  {
781  DWORD dwAvailable = 0;
782  PeekNamedPipe(
783  g_hChildStd_OUT_Rd, NULL, NULL, NULL, &dwAvailable, NULL);
784  if (dwAvailable)
785  {
786  bSuccess = ReadFile(
787  g_hChildStd_OUT_Rd, chBuf, sizeof(chBuf), &dwRead, NULL);
788  if (!bSuccess || dwRead == 0) break;
789  sout.write(chBuf, dwRead);
790  }
791  else
792  {
793  // process ended?
794  if (GetExitCodeProcess(piProcInfo.hProcess, &exitval))
795  {
796  if (exitval != STILL_ACTIVE)
797  {
798  exit_code = exitval;
799  break;
800  }
801  }
802  }
803  }
804 
805  // Close handles to the child process and its primary thread.
806  CloseHandle(piProcInfo.hProcess);
807  CloseHandle(piProcInfo.hThread);
808  }
809  catch (std::string& errStr)
810  {
811  std::cerr << errStr;
812  return 1; // !=0 means error
813  }
814 #endif
815  // set output - if valid pointer given
816  if (output)
817  {
818  *output = sout.str();
819  }
820 
821  // Return exit code
822  return exit_code;
823 } // end of executeCommand
824 
826 {
827 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
828  void* handle = nullptr;
829 #endif
830 #ifdef MRPT_OS_WINDOWS
831  HMODULE handle;
832 #endif
833 };
834 
836 {
838  {
839  static ModulesRegistry obj;
840  return obj;
841  }
842 
843  ModulesRegistry() = default;
845  {
846  try
847  {
848  // Make a copy, since each unload() call would invalidate iterators
849  // to the changing list "loadedModules":
850  loadedModules_mtx.lock();
851  auto lstCopy = loadedModules;
852  loadedModules_mtx.unlock();
853 
854  for (auto& ent : lstCopy) unloadPluginModule(ent.first);
855  }
856  catch (const std::exception& e)
857  {
858  std::cerr << "[~ModulesRegistry] Exception: "
860  }
861  }
862 
863  using full_path_t = std::string;
864  std::map<full_path_t, LoadedModuleInfo> loadedModules;
865  std::mutex loadedModules_mtx;
866 };
867 
869  const std::string& moduleFileName,
870  mrpt::optional_ref<std::string> outErrorMsgs)
871 {
872  auto& md = ModulesRegistry::Instance();
873  std::lock_guard<std::mutex> lck(md.loadedModules_mtx);
874 
875  std::string sError;
876 
877 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
878  void* handle = dlopen(moduleFileName.c_str(), RTLD_LAZY);
879 #elif defined(MRPT_OS_WINDOWS)
880  HMODULE handle = LoadLibraryA(moduleFileName.c_str());
881 #else
882  void* handle = nullptr;
883  sError = "Unsupported OS";
884 #endif
885 
886  if (handle)
887  {
888  // register for future dlclose()
889  md.loadedModules[moduleFileName].handle = handle;
890  return true;
891  }
892 
893 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
894  sError = mrpt::format(
895  "Error loading '%s':\n%s\n", moduleFileName.c_str(), dlerror());
896 #elif defined(MRPT_OS_WINDOWS)
897  sError = mrpt::format(
898  "Error loading '%s':\nWindows error: %u\n", moduleFileName.c_str(),
899  GetLastError());
900 #endif
901 
902  if (outErrorMsgs)
903  outErrorMsgs.value().get() += sError;
904  else
905  std::cerr << sError;
906  return false;
907 }
908 
910  const std::string& moduleFileName,
911  mrpt::optional_ref<std::string> outErrorMsgs)
912 {
913  auto& md = ModulesRegistry::Instance();
914  std::lock_guard<std::mutex> lck(md.loadedModules_mtx);
915 
916  std::string sError;
917 
918  const auto it = md.loadedModules.find(moduleFileName);
919  if (it == md.loadedModules.end())
920  {
921  sError = "Module filename '" + moduleFileName +
922  "' not found in previous calls to loadPluginModule().";
923  }
924  else
925  {
926 #if defined(MRPT_OS_LINUX) || defined(MRPT_OS_APPLE)
927  if (0 != dlclose(it->second.handle))
928  {
929  sError = mrpt::format(
930  "Error unloading '%s':\n%s\n", moduleFileName.c_str(),
931  dlerror());
932  }
933 #elif defined(MRPT_OS_WINDOWS)
934  if (!FreeLibrary(it->second.handle))
935  {
936  sError = mrpt::format(
937  "Error unloading '%s':\nWindows error: %u\n",
938  moduleFileName.c_str(), GetLastError());
939  }
940 #endif
941  }
942 
943  if (!sError.empty())
944  {
945  if (outErrorMsgs)
946  outErrorMsgs.value().get() += sError;
947  else
948  std::cerr << sError;
949  return false;
950  }
951  else
952  {
953  md.loadedModules.erase(it);
954  return true;
955  }
956 }
957 
959  const std::string& moduleFileNames,
960  mrpt::optional_ref<std::string> outErrorMsgs)
961 {
962  std::vector<std::string> lstModules;
963  mrpt::system::tokenize(moduleFileNames, ",", lstModules);
964 
965  bool allOk = true;
966  for (const auto& sLib : lstModules)
967  if (!loadPluginModule(sLib, outErrorMsgs)) allOk = false;
968 
969  return allOk;
970 }
971 
973  const std::string& moduleFileNames,
974  mrpt::optional_ref<std::string> outErrorMsgs)
975 {
976  std::vector<std::string> lstModules;
977  mrpt::system::tokenize(moduleFileNames, ",", lstModules);
978 
979  bool allOk = true;
980  for (const auto& sLib : lstModules)
981  if (!unloadPluginModule(sLib, outErrorMsgs)) allOk = false;
982 
983  return allOk;
984 }
int int vsprintf(char *buf, size_t bufSize, const char *format, va_list args) noexcept
An OS-independent version of vsprintf (Notice the bufSize param, which may be ignored in some compile...
const char * sLicenseTextF
Definition: os.cpp:534
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
int getch() noexcept
An OS-independent version of getch, which waits until a key is pushed.
Definition: os.cpp:381
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
int _strncmp(const char *str, const char *subStr, size_t count) noexcept
An OS-independent version of strncmp.
Definition: os.cpp:347
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:286
char * strcat(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcat.
time_t timegm(struct tm *tm)
An OS-independent version of timegm (which is not present in all compilers): converts a time structur...
Definition: os.cpp:122
int _strnicmp(const char *str, const char *subStr, size_t count) noexcept
An OS-independent version of strnicmp.
Definition: os.cpp:355
void setConsoleColor(TConsoleColor color, bool changeStdErr=false)
Changes the text color in the console for the text written from now on.
Definition: os.cpp:486
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Definition: datetime.h:86
STL namespace.
std::string MRPT_getCompilationDate()
Returns the MRPT source code timestamp, according to the Reproducible-Builds specifications: https://...
Definition: os.cpp:165
std::optional< std::reference_wrapper< T > > optional_ref
Shorter name for std::optional<std::reference_wrapper<T>>
Definition: optional_ref.h:20
std::mutex loadedModules_mtx
Definition: os.cpp:865
char * strcpy(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcpy.
void tokenize(const std::string &inString, const std::string &inDelimiters, OUT_CONTAINER &outTokens, bool skipBlankTokens=true) noexcept
Tokenizes a string according to a set of delimiting characters.
~ModulesRegistry()
Definition: os.cpp:844
std::string find_mrpt_shared_dir()
Finds the "[MRPT]/share/mrpt/" directory, if available in the system.
Definition: os.cpp:621
std::string winerror2str(const char *errorPlaceName)
Definition: os.cpp:574
void clearConsole()
Clears the console window.
Definition: os.cpp:450
std::map< full_path_t, LoadedModuleInfo > loadedModules
Definition: os.cpp:864
TConsoleColor
For use in setConsoleColor.
Definition: os.h:162
bool unloadPluginModules(const std::string &moduleFileNames, mrpt::optional_ref< std::string > outErrorMsgs=std::nullopt)
Unloads "plug-in" modules loaded with loadPluginModules().
std::string full_path_t
Definition: os.cpp:863
bool loadPluginModules(const std::string &moduleFileNames, mrpt::optional_ref< std::string > outErrorMsgs=std::nullopt)
Like loadPluginModule(), but loads a comma (,) separated list of "plug-in" modules.
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:419
void pause(const std::string &msg=std::string("Press any key to continue...")) noexcept
Shows the message "Press any key to continue" (or other custom message) to the current standard outpu...
Definition: os.cpp:441
bool unloadPluginModule(const std::string &moduleFileName, mrpt::optional_ref< std::string > outErrorMsgs=std::nullopt)
Unloads "plug-in" modules loaded with loadPluginModule().
int executeCommand(const std::string &command, std::string *output=nullptr, const std::string &mode="r")
Execute Generic Shell Command.
Definition: os.cpp:670
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
bool loadPluginModule(const std::string &moduleFileName, mrpt::optional_ref< std::string > outErrorMsgs=std::nullopt)
Loads a dynamically-linked "plug-in" module (Windows: .dll, GNU/Linux: .so).
int vsnprintf(char *buf, size_t bufSize, const char *format, va_list args) noexcept
An OS-independent version of vsnprintf (Notice the bufSize param, which may be ignored in some compil...
Definition: os.cpp:241
bool kbhit() noexcept
An OS-independent version of kbhit, which returns true if a key has been pushed.
Definition: os.cpp:403
uint64_t _strtoull(const char *nptr, char **endptr, int base)
An OS-independent version of strtoull.
Definition: os.cpp:477
static ModulesRegistry & Instance()
Definition: os.cpp:837
std::string exception_to_str(const std::exception &e)
Builds a nice textual representation of a nested exception, which if generated using MRPT macros (THR...
Definition: exceptions.cpp:59
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:268
bool directoryExists(const std::string &fileName)
Test if a given directory exists (it fails if the given path refers to an existing file)...
Definition: filesystem.cpp:137
std::string MRPT_getVersion()
Returns a string describing the MRPT version.
Definition: os.cpp:198
int64_t _strtoll(const char *nptr, char **endptr, int base)
An OS-independent version of strtoll.
Definition: os.cpp:465
bool launchProcess(const std::string &command)
Executes the given command (which may contain a program + arguments), and waits until it finishes...
Definition: os.cpp:591
const std::string & getMRPTLicense()
Returns a const ref to a text with the same text that appears at the beginning of each MRPT file (use...
Definition: os.cpp:551
std::string extractFileDirectory(const std::string &filePath)
Extract the whole path (the directory) of a filename from a complete path plus name plus extension...
Definition: filesystem.cpp:78
int _strcmp(const char *str1, const char *str2) noexcept
An OS-independent version of strcmp.
Definition: os.cpp:323
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
int _strcmpi(const char *str1, const char *str2) noexcept
An OS-independent version of strcmpi.
Definition: os.cpp:331



Page generated by Doxygen 1.8.14 for MRPT 2.0.4 Git: 33de1d0ad Sat Jun 20 11:02:42 2020 +0200 at sáb jun 20 17:35:17 CEST 2020