Rev 18 | Rev 23 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 16 | pmbaty | 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 | ||
| 19 | pmbaty | 27 | #include <stdarg.h> | 
| 28 | #include <io.h> | ||
| 29 | #include <direct.h> | ||
| 16 | pmbaty | 30 | #if defined(_M_AMD64) | 
| 31 | #define __x86_64__ 1 | ||
| 32 | #elif defined(_M_ARM64) || defined(_M_ARM64EC) | ||
| 33 | #define __aarch64__ 1 | ||
| 34 | #endif // native platform identification | ||
| 35 | 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... | ||
| 36 | #define strerror(n) sane_strerror ((n)) // STFU Microsoft | ||
| 37 | 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. | ||
| 38 | #define getenv(v) sane_getenv ((v)) // STFU Microsoft | ||
| 39 | 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. | ||
| 40 | #define localtime(t) sane_localtime ((t)) // STFU Microsoft | ||
| 41 | 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. | ||
| 42 | #define asctime(t) sane_asctime ((t)) // STFU Microsoft | ||
| 19 | pmbaty | 43 | static inline int vasprintf (char **out_string, const char *fmt, va_list va_args) { int retval; va_list ap; va_copy (ap, va_args); retval = _vsnprintf_s (NULL, 0, 0, fmt, ap); va_end (ap); if (retval == -1) return (-1); *out_string = malloc ((size_t) retval + 1); if (*out_string == NULL) return (-1); va_copy (ap, va_args); retval = _vsnprintf_s (*out_string, (size_t) retval + 1, (size_t) retval + 1, fmt, va_args); va_end (ap); return (retval); } // vasprintf() implementation for Windows | 
| 44 | static inline int asprintf (char **out_string, const char *fmt, ...) { int r; va_list ap; va_start (ap, fmt); r = vasprintf (out_string, fmt, ap); va_end (ap); return (r); } // asprintf() implementation for Windows | ||
| 45 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) | ||
| 46 | #define __builtin_bswap16(x) _byteswap_ushort ((unsigned short) (x)) | ||
| 47 | #define __builtin_bswap32(x) _byteswap_ulong ((unsigned long) (x)) | ||
| 48 | #define __ORDER_LITTLE_ENDIAN__ 1234 | ||
| 49 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ // all Windows machines are little-endian | ||
| 16 | pmbaty | 50 | #define S_IFIFO 0x1000 | 
| 51 | #define S_IFLNK 0xa000 | ||
| 18 | pmbaty | 52 | #define S_ISDIR(m)  (((m) & S_IFMT) == S_IFDIR) | 
| 53 | #define S_ISREG(m)  (((m) & S_IFMT) == S_IFREG) | ||
| 54 | #define S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK) | ||
| 55 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) | ||
| 19 | pmbaty | 56 | #define major(rdev) ((int) (((rdev) >> 10) & 0x3f)) // on Windows assume a QNX-compatible makedev(). Node is zero (local host). | 
| 57 | #define minor(rdev) ((int) (((rdev) >> 0) & 0x3ff)) // on Windows assume a QNX-compatible makedev(). Node is zero (local host). | ||
| 58 | #define makedev(maj,min) ((dev_t) (((maj) << 10) | (min))) // on Windows assume a QNX-compatible makedev(). Node is zero (local host). | ||
| 16 | pmbaty | 59 | #define strdup(s) _strdup ((s)) | 
| 60 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) | ||
| 61 | #define strtok_r(s,delim,ctx) strtok_s ((s), (delim), (ctx)) | ||
| 19 | pmbaty | 62 | #define mkdir(pathname,mode) _mkdir ((pathname)) | 
| 16 | pmbaty | 63 | #define utimbuf __utimbuf32 | 
| 64 | #define utime(p,t) _utime32 ((p), (t)) | ||
| 19 | pmbaty | 65 | #define access(pathname,accmode) _access ((pathname), (accmode)) | 
| 66 | #define unlink(pathname) _unlink ((pathname)) | ||
| 67 | #define ftello(fp) _ftelli64 ((fp)) | ||
| 68 | #define fileno(fp) _fileno ((fp)) | ||
| 69 | #define ftruncate(fd,size) _chsize_s ((fd), (size)) | ||
| 70 | #define readlink(pathname,buf,maxsize) ((*_errno () = 129 /*ENOTSUP*/), -1) // readlink() not supported on Windows | ||
| 71 | #define stat _stat64 | ||
| 72 | #define getcwd(buf,maxsize) _getcwd ((buf), (maxsize)) | ||
| 73 | #define chdir(pathname) _chdir ((pathname)) | ||
| 74 | #define putenv(v) _putenv ((v)) | ||
| 16 | pmbaty | 75 | #define MAXPATHLEN 1024 | 
| 19 | pmbaty | 76 | struct dirent { unsigned char d_namlen; char *d_name; }; // bring struct dirent/opendir() support to Windows | 
| 77 | typedef struct DIR { intptr_t handle; struct __finddata64_t info; struct dirent result; char *pathname; char *search_pattern; } DIR; | ||
| 78 | static inline DIR *opendir (const char *name) // UNIX-like opendir() implementation for Windows | ||
| 79 | { | ||
| 80 | DIR *dir; size_t base_length, all_length; const char *suffix; | ||
| 81 | dir = (DIR *) malloc (sizeof (DIR)); if (dir == NULL) { /*errno already set*/ return (NULL); } | ||
| 82 | dir->pathname = _fullpath (NULL, name, 0); // system will mallocate, caller frees | ||
| 83 | if (dir->pathname == NULL) { free (dir); *_errno () = 12 /*ENOMEM*/; return (NULL); } | ||
| 84 | base_length = strlen (name); | ||
| 85 | suffix = ((name[base_length - 1] == '\\') || (name[base_length - 1] == '/') ? "*" : "/*"); // search pattern must end with suitable wildcard | ||
| 86 | all_length = base_length + strlen (suffix) + 1; | ||
| 87 | dir->search_pattern = (char *) malloc (all_length); if (dir->search_pattern == NULL) { free (dir->pathname); free (dir); *_errno () = 12 /*ENOMEM*/; return (NULL); } | ||
| 88 | strcpy_s (dir->search_pattern, all_length, name); strcat_s (dir->search_pattern, all_length, suffix); | ||
| 89 | dir->handle = _findfirst64 (dir->search_pattern, &dir->info); if (dir->handle == -1) { free (dir->search_pattern); free (dir->pathname); free (dir); return (NULL); } | ||
| 90 | dir->result.d_namlen = 0; dir->result.d_name = NULL; // first-time initialization | ||
| 91 | return (dir); | ||
| 92 | } | ||
| 93 | static inline int closedir (DIR *dir) // UNIX-like closedir() implementation for Windows | ||
| 94 | { | ||
| 95 | int result = -1; | ||
| 96 | if (dir == NULL) { *_errno () = 9 /*EBADF*/; return (-1); } | ||
| 97 | if (dir->handle != -1) result = _findclose (dir->handle); | ||
| 98 | if (dir->search_pattern != NULL) free (dir->search_pattern); | ||
| 99 | if (dir->pathname != NULL) free (dir->pathname); | ||
| 100 | free (dir); | ||
| 101 | if (result == -1) *_errno () = 9 /*EBADF*/; // map all errors to EBADF | ||
| 102 | return (result); | ||
| 103 | } | ||
| 104 | static inline struct dirent *readdir (DIR *dir) // UNIX-like readdir() implementation for Windows | ||
| 105 | { | ||
| 106 | struct dirent *result = NULL; | ||
| 107 | if ((dir == NULL) || (dir->handle == -1)) { *_errno () = 9 /*EBADF*/; return (NULL); } | ||
| 108 | if ((dir->result.d_name == NULL) || (_findnext64 (dir->handle, &dir->info) != -1)) { | ||
| 109 | result = &dir->result; | ||
| 110 | result->d_name = dir->info.name; | ||
| 111 | result->d_namlen = (unsigned char) strlen (dir->info.name); | ||
| 112 |    } | ||
| 113 | return (result); | ||
| 114 | } | ||
| 115 | static inline void rewinddir (DIR *dir) // UNIX-like rewinddir() implementation for Windows | ||
| 116 | { | ||
| 117 | if ((dir == NULL) || (dir->handle == -1)) { *_errno () = 9 /*EBADF*/; return; } | ||
| 118 | _findclose (dir->handle); | ||
| 119 | dir->handle = (long) _findfirst64 (dir->search_pattern, &dir->info); | ||
| 120 | dir->result.d_namlen = 0; dir->result.d_name = NULL; // first-time initialization | ||
| 121 | } | ||
| 16 | pmbaty | 122 | #else // !_MSC_VER | 
| 123 | #define strcpy_s(s1,s1size,s2) strcpy ((s1), (s2)) | ||
| 124 | #define strcat_s(s1,s1size,s2) strcat ((s1), (s2)) | ||
| 125 | #define sprintf_s(s1,s1size,...) sprintf ((s1), __VA_ARGS__) | ||
| 126 | #define fopen_s(fp,pathname,mode) *(fp) = fopen ((pathname), (mode)) | ||
| 127 | #endif // _MSC_VER | ||
| 128 | |||
| 129 | |||
| 130 | // 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); | ||
| 131 | #ifndef VERSION_ARG_YYYYMMDD | ||
| 132 | #define BUILDDATE_YEAR  (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021" | ||
| 133 | #define BUILDDATE_MONTH ( \ | ||
| 134 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \ | ||
| 135 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \ | ||
| 136 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \ | ||
| 137 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \ | ||
| 138 |    *((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \ | ||
| 139 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \ | ||
| 140 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \ | ||
| 141 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \ | ||
| 142 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \ | ||
| 143 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \ | ||
| 144 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \ | ||
| 145 |    *((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : \ | ||
| 146 |    "XX" \ | ||
| 147 | ) // compiler will optimize this into a const string, e.g. "11" | ||
| 148 | #define BUILDDATE_DAY ( \ | ||
| 149 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  1 ") ? "01" : \ | ||
| 150 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  2 ") ? "02" : \ | ||
| 151 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  3 ") ? "03" : \ | ||
| 152 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  4 ") ? "04" : \ | ||
| 153 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  5 ") ? "05" : \ | ||
| 154 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  6 ") ? "06" : \ | ||
| 155 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  7 ") ? "07" : \ | ||
| 156 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  8 ") ? "08" : \ | ||
| 157 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  9 ") ? "09" : \ | ||
| 158 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \ | ||
| 159 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \ | ||
| 160 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \ | ||
| 161 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \ | ||
| 162 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \ | ||
| 163 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \ | ||
| 164 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \ | ||
| 165 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \ | ||
| 166 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \ | ||
| 167 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \ | ||
| 168 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \ | ||
| 169 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \ | ||
| 170 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \ | ||
| 171 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \ | ||
| 172 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \ | ||
| 173 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \ | ||
| 174 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \ | ||
| 175 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \ | ||
| 176 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \ | ||
| 177 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \ | ||
| 178 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ | ||
| 179 |    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \ | ||
| 180 |    "XX" \ | ||
| 181 | ) // compiler will optimize this into a const string, e.g. "14" | ||
| 182 | #define VERSION_FMT_YYYYMMDD "%s%s%s" | ||
| 183 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY | ||
| 184 | #endif // !VERSION_ARG_YYYYMMDD | ||
| 185 | |||
| 186 | |||
| 187 | // macro to bring __FILE_NAME__ support to moronic compilers | ||
| 188 | #ifndef __FILE_NAME__ // Clang 9+ has the macro, GCC 12+ added it too in 2021, MSVC obviously won't do it. Heh. | ||
| 189 | #define __FILE_NAME__ ( \ | ||
| 190 |    (sizeof (__FILE__) >  2) && ((__FILE__[sizeof (__FILE__) -  2] == '/') || (__FILE__[sizeof (__FILE__) -  2] == '\\')) ? &__FILE__[sizeof (__FILE__) -  1] : \ | ||
| 191 |    (sizeof (__FILE__) >  3) && ((__FILE__[sizeof (__FILE__) -  3] == '/') || (__FILE__[sizeof (__FILE__) -  3] == '\\')) ? &__FILE__[sizeof (__FILE__) -  2] : \ | ||
| 192 |    (sizeof (__FILE__) >  4) && ((__FILE__[sizeof (__FILE__) -  4] == '/') || (__FILE__[sizeof (__FILE__) -  4] == '\\')) ? &__FILE__[sizeof (__FILE__) -  3] : \ | ||
| 193 |    (sizeof (__FILE__) >  5) && ((__FILE__[sizeof (__FILE__) -  5] == '/') || (__FILE__[sizeof (__FILE__) -  5] == '\\')) ? &__FILE__[sizeof (__FILE__) -  4] : \ | ||
| 194 |    (sizeof (__FILE__) >  6) && ((__FILE__[sizeof (__FILE__) -  6] == '/') || (__FILE__[sizeof (__FILE__) -  6] == '\\')) ? &__FILE__[sizeof (__FILE__) -  5] : \ | ||
| 195 |    (sizeof (__FILE__) >  7) && ((__FILE__[sizeof (__FILE__) -  7] == '/') || (__FILE__[sizeof (__FILE__) -  7] == '\\')) ? &__FILE__[sizeof (__FILE__) -  6] : \ | ||
| 196 |    (sizeof (__FILE__) >  8) && ((__FILE__[sizeof (__FILE__) -  8] == '/') || (__FILE__[sizeof (__FILE__) -  8] == '\\')) ? &__FILE__[sizeof (__FILE__) -  7] : \ | ||
| 197 |    (sizeof (__FILE__) >  9) && ((__FILE__[sizeof (__FILE__) -  9] == '/') || (__FILE__[sizeof (__FILE__) -  9] == '\\')) ? &__FILE__[sizeof (__FILE__) -  8] : \ | ||
| 198 |    (sizeof (__FILE__) > 10) && ((__FILE__[sizeof (__FILE__) - 10] == '/') || (__FILE__[sizeof (__FILE__) - 10] == '\\')) ? &__FILE__[sizeof (__FILE__) -  9] : \ | ||
| 199 |    (sizeof (__FILE__) > 11) && ((__FILE__[sizeof (__FILE__) - 11] == '/') || (__FILE__[sizeof (__FILE__) - 11] == '\\')) ? &__FILE__[sizeof (__FILE__) - 10] : \ | ||
| 200 |    (sizeof (__FILE__) > 12) && ((__FILE__[sizeof (__FILE__) - 12] == '/') || (__FILE__[sizeof (__FILE__) - 12] == '\\')) ? &__FILE__[sizeof (__FILE__) - 11] : \ | ||
| 201 |    (sizeof (__FILE__) > 13) && ((__FILE__[sizeof (__FILE__) - 13] == '/') || (__FILE__[sizeof (__FILE__) - 13] == '\\')) ? &__FILE__[sizeof (__FILE__) - 12] : \ | ||
| 202 |    (sizeof (__FILE__) > 14) && ((__FILE__[sizeof (__FILE__) - 14] == '/') || (__FILE__[sizeof (__FILE__) - 14] == '\\')) ? &__FILE__[sizeof (__FILE__) - 13] : \ | ||
| 203 |    (sizeof (__FILE__) > 15) && ((__FILE__[sizeof (__FILE__) - 15] == '/') || (__FILE__[sizeof (__FILE__) - 15] == '\\')) ? &__FILE__[sizeof (__FILE__) - 14] : \ | ||
| 204 |    (sizeof (__FILE__) > 16) && ((__FILE__[sizeof (__FILE__) - 16] == '/') || (__FILE__[sizeof (__FILE__) - 16] == '\\')) ? &__FILE__[sizeof (__FILE__) - 15] : \ | ||
| 205 |    (sizeof (__FILE__) > 17) && ((__FILE__[sizeof (__FILE__) - 17] == '/') || (__FILE__[sizeof (__FILE__) - 17] == '\\')) ? &__FILE__[sizeof (__FILE__) - 16] : \ | ||
| 206 |    (sizeof (__FILE__) > 18) && ((__FILE__[sizeof (__FILE__) - 18] == '/') || (__FILE__[sizeof (__FILE__) - 18] == '\\')) ? &__FILE__[sizeof (__FILE__) - 17] : \ | ||
| 207 |    (sizeof (__FILE__) > 19) && ((__FILE__[sizeof (__FILE__) - 19] == '/') || (__FILE__[sizeof (__FILE__) - 19] == '\\')) ? &__FILE__[sizeof (__FILE__) - 18] : \ | ||
| 208 |    (sizeof (__FILE__) > 20) && ((__FILE__[sizeof (__FILE__) - 20] == '/') || (__FILE__[sizeof (__FILE__) - 20] == '\\')) ? &__FILE__[sizeof (__FILE__) - 19] : \ | ||
| 209 |    (sizeof (__FILE__) > 21) && ((__FILE__[sizeof (__FILE__) - 21] == '/') || (__FILE__[sizeof (__FILE__) - 21] == '\\')) ? &__FILE__[sizeof (__FILE__) - 20] : \ | ||
| 210 |    (sizeof (__FILE__) > 22) && ((__FILE__[sizeof (__FILE__) - 22] == '/') || (__FILE__[sizeof (__FILE__) - 22] == '\\')) ? &__FILE__[sizeof (__FILE__) - 21] : \ | ||
| 211 |    (sizeof (__FILE__) > 23) && ((__FILE__[sizeof (__FILE__) - 23] == '/') || (__FILE__[sizeof (__FILE__) - 23] == '\\')) ? &__FILE__[sizeof (__FILE__) - 22] : \ | ||
| 212 |    (sizeof (__FILE__) > 24) && ((__FILE__[sizeof (__FILE__) - 24] == '/') || (__FILE__[sizeof (__FILE__) - 24] == '\\')) ? &__FILE__[sizeof (__FILE__) - 23] : \ | ||
| 213 |    (sizeof (__FILE__) > 25) && ((__FILE__[sizeof (__FILE__) - 25] == '/') || (__FILE__[sizeof (__FILE__) - 25] == '\\')) ? &__FILE__[sizeof (__FILE__) - 24] : \ | ||
| 214 |    (sizeof (__FILE__) > 26) && ((__FILE__[sizeof (__FILE__) - 26] == '/') || (__FILE__[sizeof (__FILE__) - 26] == '\\')) ? &__FILE__[sizeof (__FILE__) - 25] : \ | ||
| 215 |    (sizeof (__FILE__) > 27) && ((__FILE__[sizeof (__FILE__) - 27] == '/') || (__FILE__[sizeof (__FILE__) - 27] == '\\')) ? &__FILE__[sizeof (__FILE__) - 26] : \ | ||
| 216 |    (sizeof (__FILE__) > 28) && ((__FILE__[sizeof (__FILE__) - 28] == '/') || (__FILE__[sizeof (__FILE__) - 28] == '\\')) ? &__FILE__[sizeof (__FILE__) - 27] : \ | ||
| 217 |    (sizeof (__FILE__) > 29) && ((__FILE__[sizeof (__FILE__) - 29] == '/') || (__FILE__[sizeof (__FILE__) - 29] == '\\')) ? &__FILE__[sizeof (__FILE__) - 28] : \ | ||
| 218 |    (sizeof (__FILE__) > 30) && ((__FILE__[sizeof (__FILE__) - 30] == '/') || (__FILE__[sizeof (__FILE__) - 30] == '\\')) ? &__FILE__[sizeof (__FILE__) - 29] : \ | ||
| 219 |    (sizeof (__FILE__) > 31) && ((__FILE__[sizeof (__FILE__) - 31] == '/') || (__FILE__[sizeof (__FILE__) - 31] == '\\')) ? &__FILE__[sizeof (__FILE__) - 30] : \ | ||
| 220 |    (sizeof (__FILE__) > 32) && ((__FILE__[sizeof (__FILE__) - 32] == '/') || (__FILE__[sizeof (__FILE__) - 32] == '\\')) ? &__FILE__[sizeof (__FILE__) - 31] : \ | ||
| 221 |    (sizeof (__FILE__) > 33) && ((__FILE__[sizeof (__FILE__) - 33] == '/') || (__FILE__[sizeof (__FILE__) - 33] == '\\')) ? &__FILE__[sizeof (__FILE__) - 32] : \ | ||
| 222 |    __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. | ||
| 223 | #endif // !__FILE_NAME__ | ||
| 224 | |||
| 225 | |||
| 226 | // logging macros | ||
| 227 | #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) | ||
| 228 | #define LOG_ERROR(...)   LOG ("error",   0, __VA_ARGS__) | ||
| 229 | #define LOG_WARNING(...) LOG ("warning", 1, __VA_ARGS__) | ||
| 230 | #define LOG_INFO(...)    LOG ("info",    2, __VA_ARGS__) | ||
| 231 | #define LOG_DEBUG(...)   LOG ("debug",   3, __VA_ARGS__) | ||
| 232 | |||
| 233 | // macro to gently exit with an error message | ||
| 234 | #define DIE_WITH_EXITCODE(exitcode,...) do { LOG_ERROR (__VA_ARGS__); exit ((exitcode)); } while (0) | ||
| 235 | |||
| 236 | // macro to exit less brutally than with abort() if something doesn't go the way we'd like to | ||
| 237 | #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) | ||
| 238 | #define ASSERT_WITH_ERRNO(is_it_true) ASSERT ((is_it_true), "%s", strerror (errno)) | ||
| 239 | |||
| 240 | |||
| 241 | #ifdef __cplusplus | ||
| 242 | } | ||
| 243 | #endif | ||
| 244 | |||
| 245 | |||
| 246 | #endif // UTILITY_H |