Subversion Repositories QNX 8.QNX8 IFS tool

Rev

Rev 16 | Rev 19 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #ifndef UTILITY_H
  2. #define UTILITY_H
  3.  
  4.  
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8.  
  9.  
  10. // standard C includes
  11. #include <stdint.h>
  12. #include <time.h>
  13.  
  14.  
  15. // bring TLS support to antique compilers
  16. #ifndef thread_local
  17. #ifdef _MSC_VER
  18. #define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23
  19. #else // a saner compiler
  20. #define thread_local _Thread_local // the thread_local keyword wasn't defined before C++11 and C23
  21. #endif // _MSC_VER
  22. #endif // !thread_local
  23.  
  24.  
  25. // Microsoft-specific shims
  26. #ifdef _MSC_VER
  27. #if defined(_M_AMD64)
  28. #define __x86_64__ 1
  29. #elif defined(_M_ARM64) || defined(_M_ARM64EC)
  30. #define __aarch64__ 1
  31. #endif // native platform identification
  32. static inline char *sane_strerror (int errnum) { thread_local static char errorstr[256]; strerror_s (errorstr, sizeof (errorstr), errnum); return (errorstr); } // non-complaining strerror() implementation for MSVC. Note that strerror() is unsafe IF AND ONLY IF the locale is changed during program execution AND a string pointer returned by strerror is saved and reused by the program. Guess the odds it will happen here...
  33. #define strerror(n) sane_strerror ((n)) // STFU Microsoft
  34. static inline char *sane_getenv (const char *varname) { extern char **environ; size_t i, len = strlen (varname); for (i = 0; environ[i] != NULL; i++) if ((strncmp (environ[i], varname, len) == 0) && ((environ[i])[len] == '=')) return (&(environ[i])[len + 1]); return (NULL); } // non-complaining getenv() implementation for MSVC. Note that getenv_s() access _environ too as per Microsoft docs, so this is perfectly legit. Nuff said.
  35. #define getenv(v) sane_getenv ((v)) // STFU Microsoft
  36. static struct tm *sane_localtime (const time_t *clock) { thread_local static struct tm localtime_tm; if (localtime_s (&localtime_tm, clock) != 0) return (NULL); return (&localtime_tm); } // non-complaining localtime() implementation for MSVC. Uses TLS.
  37. #define localtime(t) sane_localtime ((t)) // STFU Microsoft
  38. static inline char *sane_asctime (const struct tm *tm_time) { thread_local static char asctimestr[64]; if (asctime_s (asctimestr, sizeof (asctimestr), tm_time) != 0) return (NULL); return (asctimestr); } // non-complaining asctime() implementation for MSVC. Uses TLS.
  39. #define asctime(t) sane_asctime ((t)) // STFU Microsoft
  40. #define S_IFIFO 0x1000
  41. #define S_IFLNK 0xa000
  42. #define S_ISDIR(m)  (((m) & S_IFMT) == S_IFDIR)
  43. #define S_ISREG(m)  (((m) & S_IFMT) == S_IFREG)
  44. #define S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK)
  45. #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
  46. #define strdup(s) _strdup ((s))
  47. #define strcasecmp(s1,s2) _stricmp ((s1), (s2))
  48. #define strtok_r(s,delim,ctx) strtok_s ((s), (delim), (ctx))
  49. #define mkdir(p,m) _mkdir ((p))
  50. #define utimbuf __utimbuf32
  51. #define utime(p,t) _utime32 ((p), (t))
  52. #define access(p,m) _access ((p), (m))
  53. #define MAXPATHLEN 1024
  54. #else // !_MSC_VER
  55. #define strcpy_s(s1,s1size,s2) strcpy ((s1), (s2))
  56. #define strcat_s(s1,s1size,s2) strcat ((s1), (s2))
  57. #define sprintf_s(s1,s1size,...) sprintf ((s1), __VA_ARGS__)
  58. #define fopen_s(fp,pathname,mode) *(fp) = fopen ((pathname), (mode))
  59. #endif // _MSC_VER
  60.  
  61.  
  62. // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
  63. #ifndef VERSION_ARG_YYYYMMDD
  64. #define BUILDDATE_YEAR  (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021"
  65. #define BUILDDATE_MONTH ( \
  66.    *((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \
  67.    *((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \
  68.    *((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \
  69.    *((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \
  70.    *((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \
  71.    *((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \
  72.    *((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \
  73.    *((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \
  74.    *((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \
  75.    *((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \
  76.    *((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \
  77.    *((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : \
  78.    "XX" \
  79. ) // compiler will optimize this into a const string, e.g. "11"
  80. #define BUILDDATE_DAY ( \
  81.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  1 ") ? "01" : \
  82.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  2 ") ? "02" : \
  83.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  3 ") ? "03" : \
  84.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  4 ") ? "04" : \
  85.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  5 ") ? "05" : \
  86.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  6 ") ? "06" : \
  87.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  7 ") ? "07" : \
  88.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  8 ") ? "08" : \
  89.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  9 ") ? "09" : \
  90.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \
  91.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \
  92.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \
  93.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \
  94.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \
  95.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \
  96.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \
  97.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \
  98.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \
  99.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \
  100.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \
  101.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \
  102.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \
  103.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \
  104.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \
  105.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \
  106.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \
  107.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \
  108.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \
  109.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \
  110.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \
  111.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \
  112.    "XX" \
  113. ) // compiler will optimize this into a const string, e.g. "14"
  114. #define VERSION_FMT_YYYYMMDD "%s%s%s"
  115. #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY
  116. #endif // !VERSION_ARG_YYYYMMDD
  117.  
  118.  
  119. // macro to bring __FILE_NAME__ support to moronic compilers
  120. #ifndef __FILE_NAME__ // Clang 9+ has the macro, GCC 12+ added it too in 2021, MSVC obviously won't do it. Heh.
  121. #define __FILE_NAME__ ( \
  122.    (sizeof (__FILE__) >  2) && ((__FILE__[sizeof (__FILE__) -  2] == '/') || (__FILE__[sizeof (__FILE__) -  2] == '\\')) ? &__FILE__[sizeof (__FILE__) -  1] : \
  123.    (sizeof (__FILE__) >  3) && ((__FILE__[sizeof (__FILE__) -  3] == '/') || (__FILE__[sizeof (__FILE__) -  3] == '\\')) ? &__FILE__[sizeof (__FILE__) -  2] : \
  124.    (sizeof (__FILE__) >  4) && ((__FILE__[sizeof (__FILE__) -  4] == '/') || (__FILE__[sizeof (__FILE__) -  4] == '\\')) ? &__FILE__[sizeof (__FILE__) -  3] : \
  125.    (sizeof (__FILE__) >  5) && ((__FILE__[sizeof (__FILE__) -  5] == '/') || (__FILE__[sizeof (__FILE__) -  5] == '\\')) ? &__FILE__[sizeof (__FILE__) -  4] : \
  126.    (sizeof (__FILE__) >  6) && ((__FILE__[sizeof (__FILE__) -  6] == '/') || (__FILE__[sizeof (__FILE__) -  6] == '\\')) ? &__FILE__[sizeof (__FILE__) -  5] : \
  127.    (sizeof (__FILE__) >  7) && ((__FILE__[sizeof (__FILE__) -  7] == '/') || (__FILE__[sizeof (__FILE__) -  7] == '\\')) ? &__FILE__[sizeof (__FILE__) -  6] : \
  128.    (sizeof (__FILE__) >  8) && ((__FILE__[sizeof (__FILE__) -  8] == '/') || (__FILE__[sizeof (__FILE__) -  8] == '\\')) ? &__FILE__[sizeof (__FILE__) -  7] : \
  129.    (sizeof (__FILE__) >  9) && ((__FILE__[sizeof (__FILE__) -  9] == '/') || (__FILE__[sizeof (__FILE__) -  9] == '\\')) ? &__FILE__[sizeof (__FILE__) -  8] : \
  130.    (sizeof (__FILE__) > 10) && ((__FILE__[sizeof (__FILE__) - 10] == '/') || (__FILE__[sizeof (__FILE__) - 10] == '\\')) ? &__FILE__[sizeof (__FILE__) -  9] : \
  131.    (sizeof (__FILE__) > 11) && ((__FILE__[sizeof (__FILE__) - 11] == '/') || (__FILE__[sizeof (__FILE__) - 11] == '\\')) ? &__FILE__[sizeof (__FILE__) - 10] : \
  132.    (sizeof (__FILE__) > 12) && ((__FILE__[sizeof (__FILE__) - 12] == '/') || (__FILE__[sizeof (__FILE__) - 12] == '\\')) ? &__FILE__[sizeof (__FILE__) - 11] : \
  133.    (sizeof (__FILE__) > 13) && ((__FILE__[sizeof (__FILE__) - 13] == '/') || (__FILE__[sizeof (__FILE__) - 13] == '\\')) ? &__FILE__[sizeof (__FILE__) - 12] : \
  134.    (sizeof (__FILE__) > 14) && ((__FILE__[sizeof (__FILE__) - 14] == '/') || (__FILE__[sizeof (__FILE__) - 14] == '\\')) ? &__FILE__[sizeof (__FILE__) - 13] : \
  135.    (sizeof (__FILE__) > 15) && ((__FILE__[sizeof (__FILE__) - 15] == '/') || (__FILE__[sizeof (__FILE__) - 15] == '\\')) ? &__FILE__[sizeof (__FILE__) - 14] : \
  136.    (sizeof (__FILE__) > 16) && ((__FILE__[sizeof (__FILE__) - 16] == '/') || (__FILE__[sizeof (__FILE__) - 16] == '\\')) ? &__FILE__[sizeof (__FILE__) - 15] : \
  137.    (sizeof (__FILE__) > 17) && ((__FILE__[sizeof (__FILE__) - 17] == '/') || (__FILE__[sizeof (__FILE__) - 17] == '\\')) ? &__FILE__[sizeof (__FILE__) - 16] : \
  138.    (sizeof (__FILE__) > 18) && ((__FILE__[sizeof (__FILE__) - 18] == '/') || (__FILE__[sizeof (__FILE__) - 18] == '\\')) ? &__FILE__[sizeof (__FILE__) - 17] : \
  139.    (sizeof (__FILE__) > 19) && ((__FILE__[sizeof (__FILE__) - 19] == '/') || (__FILE__[sizeof (__FILE__) - 19] == '\\')) ? &__FILE__[sizeof (__FILE__) - 18] : \
  140.    (sizeof (__FILE__) > 20) && ((__FILE__[sizeof (__FILE__) - 20] == '/') || (__FILE__[sizeof (__FILE__) - 20] == '\\')) ? &__FILE__[sizeof (__FILE__) - 19] : \
  141.    (sizeof (__FILE__) > 21) && ((__FILE__[sizeof (__FILE__) - 21] == '/') || (__FILE__[sizeof (__FILE__) - 21] == '\\')) ? &__FILE__[sizeof (__FILE__) - 20] : \
  142.    (sizeof (__FILE__) > 22) && ((__FILE__[sizeof (__FILE__) - 22] == '/') || (__FILE__[sizeof (__FILE__) - 22] == '\\')) ? &__FILE__[sizeof (__FILE__) - 21] : \
  143.    (sizeof (__FILE__) > 23) && ((__FILE__[sizeof (__FILE__) - 23] == '/') || (__FILE__[sizeof (__FILE__) - 23] == '\\')) ? &__FILE__[sizeof (__FILE__) - 22] : \
  144.    (sizeof (__FILE__) > 24) && ((__FILE__[sizeof (__FILE__) - 24] == '/') || (__FILE__[sizeof (__FILE__) - 24] == '\\')) ? &__FILE__[sizeof (__FILE__) - 23] : \
  145.    (sizeof (__FILE__) > 25) && ((__FILE__[sizeof (__FILE__) - 25] == '/') || (__FILE__[sizeof (__FILE__) - 25] == '\\')) ? &__FILE__[sizeof (__FILE__) - 24] : \
  146.    (sizeof (__FILE__) > 26) && ((__FILE__[sizeof (__FILE__) - 26] == '/') || (__FILE__[sizeof (__FILE__) - 26] == '\\')) ? &__FILE__[sizeof (__FILE__) - 25] : \
  147.    (sizeof (__FILE__) > 27) && ((__FILE__[sizeof (__FILE__) - 27] == '/') || (__FILE__[sizeof (__FILE__) - 27] == '\\')) ? &__FILE__[sizeof (__FILE__) - 26] : \
  148.    (sizeof (__FILE__) > 28) && ((__FILE__[sizeof (__FILE__) - 28] == '/') || (__FILE__[sizeof (__FILE__) - 28] == '\\')) ? &__FILE__[sizeof (__FILE__) - 27] : \
  149.    (sizeof (__FILE__) > 29) && ((__FILE__[sizeof (__FILE__) - 29] == '/') || (__FILE__[sizeof (__FILE__) - 29] == '\\')) ? &__FILE__[sizeof (__FILE__) - 28] : \
  150.    (sizeof (__FILE__) > 30) && ((__FILE__[sizeof (__FILE__) - 30] == '/') || (__FILE__[sizeof (__FILE__) - 30] == '\\')) ? &__FILE__[sizeof (__FILE__) - 29] : \
  151.    (sizeof (__FILE__) > 31) && ((__FILE__[sizeof (__FILE__) - 31] == '/') || (__FILE__[sizeof (__FILE__) - 31] == '\\')) ? &__FILE__[sizeof (__FILE__) - 30] : \
  152.    (sizeof (__FILE__) > 32) && ((__FILE__[sizeof (__FILE__) - 32] == '/') || (__FILE__[sizeof (__FILE__) - 32] == '\\')) ? &__FILE__[sizeof (__FILE__) - 31] : \
  153.    (sizeof (__FILE__) > 33) && ((__FILE__[sizeof (__FILE__) - 33] == '/') || (__FILE__[sizeof (__FILE__) - 33] == '\\')) ? &__FILE__[sizeof (__FILE__) - 32] : \
  154.    __FILE__) // this *COMPILE-TIME* macro complements the __FILE__ macro defined by the C standard by returning just the filename portion of the full path. Supports filenames up to 32 chars. Expand as necessary.
  155. #endif // !__FILE_NAME__
  156.  
  157.  
  158. // logging macros
  159. #define LOG(type,lvl,...) do { if ((lvl) <= verbose_level) { fprintf (stderr, "ifstool: %s: ", (type)); if (verbose_level > 1) fprintf (stderr, "%s:%d:%s(): ", __FILE_NAME__, __LINE__, __func__); fprintf (stderr, __VA_ARGS__); fputc ('\n', stderr); } } while (0)
  160. #define LOG_ERROR(...)   LOG ("error",   0, __VA_ARGS__)
  161. #define LOG_WARNING(...) LOG ("warning", 1, __VA_ARGS__)
  162. #define LOG_INFO(...)    LOG ("info",    2, __VA_ARGS__)
  163. #define LOG_DEBUG(...)   LOG ("debug",   3, __VA_ARGS__)
  164.  
  165. // macro to gently exit with an error message
  166. #define DIE_WITH_EXITCODE(exitcode,...) do { LOG_ERROR (__VA_ARGS__); exit ((exitcode)); } while (0)
  167.  
  168. // macro to exit less brutally than with abort() if something doesn't go the way we'd like to
  169. #define ASSERT(is_it_true,...) do { if (!(is_it_true)) { LOG ("fatal error", 0, "consistency check failed:"); LOG ("fatal error", 0, #is_it_true); LOG ("fatal error", 0, __VA_ARGS__); exit (1); } } while (0)
  170. #define ASSERT_WITH_ERRNO(is_it_true) ASSERT ((is_it_true), "%s", strerror (errno))
  171.  
  172.  
  173. #ifdef __cplusplus
  174. }
  175. #endif
  176.  
  177.  
  178. #endif // UTILITY_H
  179.