|
| 1 | +#include <stdbool.h> |
1 | 2 | #include <stddef.h>
|
2 | 3 | #include <sys/stat.h>
|
3 | 4 | #include <sys/types.h>
|
4 | 5 | #include <string.h>
|
5 | 6 | #include <errno.h>
|
6 | 7 | #ifdef _WIN32
|
7 | 8 | #include <direct.h>
|
| 9 | +#include <windows.h> |
8 | 10 | #else
|
9 | 11 | #include <unistd.h>
|
10 | 12 | #endif /* ifdef _WIN32 */
|
11 | 13 |
|
12 |
| -// Returns the string describing the meaning of `errno` code (by calling `strerror`). |
13 |
| -char* stdlib_strerror(size_t* len){ |
| 14 | +// Wrapper to get the string describing a system syscall error. |
| 15 | +// Uses `strerr` on unix. |
| 16 | +// if `winapi` is `false`, uses the usual `strerr` on windows. |
| 17 | +// If `winapi` is `false`, uses `FormatMessage`(from windows.h) on windows. |
| 18 | +char* stdlib_strerror(size_t* len, bool winapi){ |
| 19 | + |
| 20 | + if (winapi) { |
| 21 | +#ifdef _WIN32 |
| 22 | + LPSTR err = NULL; |
| 23 | + DWORD dw = GetLastError(); |
| 24 | + |
| 25 | + FormatMessage( |
| 26 | + FORMAT_MESSAGE_ALLOCATE_BUFFER | |
| 27 | + FORMAT_MESSAGE_FROM_SYSTEM | |
| 28 | + FORMAT_MESSAGE_IGNORE_INSERTS, |
| 29 | + NULL, |
| 30 | + dw, |
| 31 | + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
| 32 | + (LPSTR) &err, |
| 33 | + 0, |
| 34 | + NULL); |
| 35 | + |
| 36 | + *len = strlen(err); |
| 37 | + return (char*) err; |
| 38 | + |
| 39 | +#endif /* ifdef _WIN32 */ |
| 40 | + } |
| 41 | + |
14 | 42 | char* err = strerror(errno);
|
15 | 43 | *len = strlen(err);
|
16 | 44 | return err;
|
@@ -44,3 +72,48 @@ int stdlib_remove_directory(const char* path){
|
44 | 72 |
|
45 | 73 | return (!code) ? 0 : errno;
|
46 | 74 | }
|
| 75 | + |
| 76 | +// Wrapper to the platform's `stat`(status of path) call. |
| 77 | +// Uses `lstat` on unix, `GetFileAttributesA` on windows. |
| 78 | +// Returns the `type` of the path, and sets the `stat`(if any errors). |
| 79 | +int stdlib_exists(const char* path, int* stat){ |
| 80 | + // All the valid types |
| 81 | + const int type_unknown = 0; |
| 82 | + const int type_regular_file = 1; |
| 83 | + const int type_directory = 2; |
| 84 | + const int type_symlink = 3; |
| 85 | + |
| 86 | + int type = type_unknown; |
| 87 | + *stat = 0; |
| 88 | + |
| 89 | +#ifdef _WIN32 |
| 90 | + DWORD attrs = GetFileAttributesA(path); |
| 91 | + |
| 92 | + if (attrs == INVALID_FILE_ATTRIBUTES) { |
| 93 | + *stat = (int) GetLastError(); |
| 94 | + return type_unknown; |
| 95 | + } |
| 96 | + |
| 97 | + if (attrs & FILE_ATTRIBUTE_NORMAL) type = type_regular_file; |
| 98 | + if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) type = type_symlink; |
| 99 | + if (attrs & FILE_ATTRIBUTE_DIRECTORY) type = type_directory; |
| 100 | +#else |
| 101 | + struct stat buf = {0}; |
| 102 | + int status; |
| 103 | + status = lstat(path, &buf); |
| 104 | + |
| 105 | + if (status == -1) { |
| 106 | + // `lstat` failed |
| 107 | + *stat = errno; |
| 108 | + return type_unknown; |
| 109 | + } |
| 110 | + |
| 111 | + switch (buf.st_mode & S_IFMT) { |
| 112 | + case S_IFREG: type = type_regular_file; break; |
| 113 | + case S_IFDIR: type = type_directory; break; |
| 114 | + case S_IFLNK: type = type_symlink; break; |
| 115 | + default: type = type_unknown; break; |
| 116 | + } |
| 117 | +#endif /* ifdef _WIN32 */ |
| 118 | + return type; |
| 119 | +} |
0 commit comments