168#define _CRT_SECURE_NO_WARNINGS (1)
181#define NOB_ASSERT assert
186#define NOB_REALLOC realloc
205# define WIN32_LEAN_AND_MEAN
212# include <shellapi.h>
214# include <sys/types.h>
215# include <sys/wait.h>
216# include <sys/stat.h>
222# define NOB_LINE_END "\r\n"
224# define NOB_LINE_END "\n"
227#if defined(__GNUC__) || defined(__clang__)
229# ifdef __MINGW_PRINTF_FORMAT
230# define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (__MINGW_PRINTF_FORMAT, STRING_INDEX, FIRST_TO_CHECK)))
232# define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (printf, STRING_INDEX, FIRST_TO_CHECK)))
236# define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK)
239#define NOB_UNUSED(value) (void)(value)
240#define NOB_TODO(message) do { fprintf(stderr, "%s:%d: TODO: %s\n", __FILE__, __LINE__, message); abort(); } while(0)
241#define NOB_UNREACHABLE(message) do { fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); abort(); } while(0)
243#define NOB_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
244#define NOB_ARRAY_GET(array, index) \
245 (NOB_ASSERT((size_t)index < NOB_ARRAY_LEN(array)), array[(size_t)index])
261#define nob_shift(xs, xs_sz) (NOB_ASSERT((xs_sz) > 0), (xs_sz)--, *(xs)++)
266#define nob_shift_args(argc, argv) nob_shift(*argv, *argc)
289#define nob_return_defer(value) do { result = (value); goto defer; } while(0)
292#ifndef NOB_DA_INIT_CAP
293#define NOB_DA_INIT_CAP 256
296#define nob_da_reserve(da, expected_capacity) \
298 if ((expected_capacity) > (da)->capacity) { \
299 if ((da)->capacity == 0) { \
300 (da)->capacity = NOB_DA_INIT_CAP; \
302 while ((expected_capacity) > (da)->capacity) { \
303 (da)->capacity *= 2; \
305 (da)->items = NOB_REALLOC((da)->items, (da)->capacity * sizeof(*(da)->items)); \
306 NOB_ASSERT((da)->items != NULL && "Buy more RAM lol"); \
311#define nob_da_append(da, item) \
313 nob_da_reserve((da), (da)->count + 1); \
314 (da)->items[(da)->count++] = (item); \
317#define nob_da_free(da) NOB_FREE((da).items)
320#define nob_da_append_many(da, new_items, new_items_count) \
322 nob_da_reserve((da), (da)->count + (new_items_count)); \
323 memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
324 (da)->count += (new_items_count); \
327#define nob_da_resize(da, new_size) \
329 nob_da_reserve((da), new_size); \
330 (da)->count = (new_size); \
333#define nob_da_last(da) (da)->items[(NOB_ASSERT((da)->count > 0), (da)->count-1)]
334#define nob_da_remove_unordered(da, i) \
337 NOB_ASSERT(j < (da)->count); \
338 (da)->items[j] = (da)->items[--(da)->count]; \
362#define nob_da_foreach(Type, it, da) for (Type *it = (da)->items; it < (da)->items + (da)->count; ++it)
374#define nob_sb_append_buf(sb, buf, size) nob_da_append_many(sb, buf, size)
377#define nob_sb_append_cstr(sb, cstr) \
379 const char *s = (cstr); \
380 size_t n = strlen(s); \
381 nob_da_append_many(sb, s, n); \
386#define nob_sb_append_null(sb) nob_da_append_many(sb, "", 1)
389#define nob_sb_free(sb) NOB_FREE((sb).items)
394#define NOB_INVALID_PROC INVALID_HANDLE_VALUE
396#define NOB_INVALID_FD INVALID_HANDLE_VALUE
399#define NOB_INVALID_PROC (-1)
401#define NOB_INVALID_FD (-1)
455#define nob_cmd_append(cmd, ...) \
456 nob_da_append_many(cmd, \
457 ((const char*[]){__VA_ARGS__}), \
458 (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*)))
460#define nob_cmd_extend(cmd, other_cmd) \
461 nob_da_append_many(cmd, (other_cmd)->items, (other_cmd)->count)
464#define nob_cmd_free(cmd) NOB_FREE(cmd.items)
467#define nob_cmd_run_async(cmd) nob_cmd_run_async_redirect(cmd, (Nob_Cmd_Redirect) {0})
486#ifndef NOB_TEMP_CAPACITY
487#define NOB_TEMP_CAPACITY (8*1024*1024)
535# if defined(__GNUC__)
536# define nob_cc(cmd) nob_cmd_append(cmd, "cc")
537# elif defined(__clang__)
538# define nob_cc(cmd) nob_cmd_append(cmd, "clang")
539# elif defined(_MSC_VER)
540# define nob_cc(cmd) nob_cmd_append(cmd, "cl.exe")
543# define nob_cc(cmd) nob_cmd_append(cmd, "cc")
548# if defined(_MSC_VER) && !defined(__clang__)
549# define nob_cc_flags(cmd) nob_cmd_append(cmd, "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS")
551# define nob_cc_flags(cmd) nob_cmd_append(cmd, "-Wall", "-Wextra")
556# if defined(_MSC_VER) && !defined(__clang__)
557# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, nob_temp_sprintf("/Fe:%s", (output_path)))
559# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, "-o", (output_path))
564# define nob_cc_inputs(cmd, ...) nob_cmd_append(cmd, __VA_ARGS__)
573#ifndef NOB_REBUILD_URSELF
575# if defined(__GNUC__)
576# define NOB_REBUILD_URSELF(binary_path, source_path) "gcc", "-o", binary_path, source_path
577# elif defined(__clang__)
578# define NOB_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
579# elif defined(_MSC_VER)
580# define NOB_REBUILD_URSELF(binary_path, source_path) "cl.exe", nob_temp_sprintf("/Fe:%s", (binary_path)), source_path
583# define NOB_REBUILD_URSELF(binary_path, source_path) "cc", "-o", binary_path, source_path
610#define NOB_GO_REBUILD_URSELF(argc, argv) nob__go_rebuild_urself(argc, argv, __FILE__, NULL)
626#define NOB_GO_REBUILD_URSELF_PLUS(argc, argv, ...) nob__go_rebuild_urself(argc, argv, __FILE__, __VA_ARGS__, NULL);
646#define nob_sb_to_sv(sb) nob_sv_from_parts((sb).items, (sb).count)
653#define SV_Arg(sv) (int) (sv).count, (sv).data
699#if !defined(_WIN32) || defined(NOB_NO_MINIRENT)
703#define WIN32_LEAN_AND_MEAN
708 char d_name[MAX_PATH+1];
711typedef struct DIR DIR;
713static DIR *opendir(
const char *dirpath);
714static struct dirent *readdir(DIR *dirp);
715static int closedir(DIR *dirp);
722NOBDEF char *nob_win32_error_message(DWORD err);
728#ifdef NOB_IMPLEMENTATION
739#ifndef NOB_WIN32_ERR_MSG_SIZE
740#define NOB_WIN32_ERR_MSG_SIZE (4 * 1024)
743NOBDEF char *nob_win32_error_message(DWORD err) {
744 static char win32ErrMsg[NOB_WIN32_ERR_MSG_SIZE] = {0};
745 DWORD errMsgSize = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, LANG_USER_DEFAULT, win32ErrMsg,
746 NOB_WIN32_ERR_MSG_SIZE, NULL);
748 if (errMsgSize == 0) {
749 if (GetLastError() != ERROR_MR_MID_NOT_FOUND) {
750 if (sprintf(win32ErrMsg,
"Could not get error message for 0x%lX", err) > 0) {
751 return (
char *)&win32ErrMsg;
756 if (sprintf(win32ErrMsg,
"Invalid Windows Error code (0x%lX)", err) > 0) {
757 return (
char *)&win32ErrMsg;
764 while (errMsgSize > 1 && isspace(win32ErrMsg[errMsgSize - 1])) {
765 win32ErrMsg[--errMsgSize] =
'\0';
776 const char *binary_path =
nob_shift(argv, argc);
788 va_start(args, source_path);
790 const char *path = va_arg(args,
const char*);
791 if (path == NULL)
break;
797 if (rebuild_is_needed < 0) exit(1);
798 if (!rebuild_is_needed) {
807 if (!
nob_rename(binary_path, old_binary_path)) exit(1);
813#ifdef NOB_EXPERIMENTAL_DELETE_OLD
826static size_t nob_temp_size = 0;
832 int result = _mkdir(path);
834 int result = mkdir(path, 0755);
837 if (errno == EEXIST) {
841 nob_log(
NOB_ERROR,
"could not create directory `%s`: %s", path, strerror(errno));
853 if (!CopyFile(src_path, dst_path, FALSE)) {
854 nob_log(
NOB_ERROR,
"Could not copy file: %s", nob_win32_error_message(GetLastError()));
861 size_t buf_size = 32*1024;
863 NOB_ASSERT(buf != NULL &&
"Buy more RAM lol!!");
866 src_fd = open(src_path, O_RDONLY);
868 nob_log(
NOB_ERROR,
"Could not open file %s: %s", src_path, strerror(errno));
872 struct stat src_stat;
873 if (fstat(src_fd, &src_stat) < 0) {
874 nob_log(
NOB_ERROR,
"Could not get mode of file %s: %s", src_path, strerror(errno));
878 dst_fd = open(dst_path, O_CREAT | O_TRUNC | O_WRONLY, src_stat.st_mode);
880 nob_log(
NOB_ERROR,
"Could not create file %s: %s", dst_path, strerror(errno));
885 ssize_t n = read(src_fd, buf, buf_size);
888 nob_log(
NOB_ERROR,
"Could not read from file %s: %s", src_path, strerror(errno));
893 ssize_t m = write(dst_fd, buf2, n);
895 nob_log(
NOB_ERROR,
"Could not write to file %s: %s", dst_path, strerror(errno));
913 for (
size_t i = 0; i < cmd.
count; ++i) {
914 const char *arg = cmd.
items[i];
915 if (arg == NULL)
break;
917 if (!strchr(arg,
' ')) {
931 for (
size_t i = 0; i < cmd.
count; ++i) {
932 const char *arg = cmd.
items[i];
933 if (arg == NULL)
break;
934 size_t len = strlen(arg);
936 if (len != 0 && NULL == strpbrk(arg,
" \t\n\v\"")) {
943 size_t backslashes = 0;
945 for (
size_t j = 0; j < len; ++j) {
952 for (
size_t k = 0; k < 1+backslashes; ++k) {
961 for (
size_t k = 0; k < backslashes; ++k) {
982 memset(&sb, 0,
sizeof(sb));
987 STARTUPINFO siStartInfo;
988 ZeroMemory(&siStartInfo,
sizeof(siStartInfo));
989 siStartInfo.cb =
sizeof(STARTUPINFO);
993 siStartInfo.hStdError = redirect.
fderr ? *redirect.
fderr : GetStdHandle(STD_ERROR_HANDLE);
994 siStartInfo.hStdOutput = redirect.
fdout ? *redirect.
fdout : GetStdHandle(STD_OUTPUT_HANDLE);
995 siStartInfo.hStdInput = redirect.
fdin ? *redirect.
fdin : GetStdHandle(STD_INPUT_HANDLE);
996 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
998 PROCESS_INFORMATION piProcInfo;
999 ZeroMemory(&piProcInfo,
sizeof(PROCESS_INFORMATION));
1001 nob__win32_cmd_quote(cmd, &sb);
1003 BOOL bSuccess = CreateProcessA(NULL, sb.
items, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);
1007 nob_log(
NOB_ERROR,
"Could not create child process for %s: %s", cmd.
items[0], nob_win32_error_message(GetLastError()));
1011 CloseHandle(piProcInfo.hThread);
1013 return piProcInfo.hProcess;
1015 pid_t cpid = fork();
1022 if (redirect.
fdin) {
1023 if (dup2(*redirect.
fdin, STDIN_FILENO) < 0) {
1024 nob_log(
NOB_ERROR,
"Could not setup stdin for child process: %s", strerror(errno));
1029 if (redirect.
fdout) {
1030 if (dup2(*redirect.
fdout, STDOUT_FILENO) < 0) {
1031 nob_log(
NOB_ERROR,
"Could not setup stdout for child process: %s", strerror(errno));
1036 if (redirect.
fderr) {
1037 if (dup2(*redirect.
fderr, STDERR_FILENO) < 0) {
1038 nob_log(
NOB_ERROR,
"Could not setup stderr for child process: %s", strerror(errno));
1049 if (execvp(cmd.
items[0], (
char *
const*) cmd_null.
items) < 0) {
1071 if (redirect.
fdin) {
1075 if (redirect.
fdout) {
1079 if (redirect.
fderr) {
1089 Nob_Fd result = open(path, O_RDONLY);
1097 SECURITY_ATTRIBUTES saAttr = {0};
1098 saAttr.nLength =
sizeof(SECURITY_ATTRIBUTES);
1099 saAttr.bInheritHandle = TRUE;
1101 Nob_Fd result = CreateFile(
1107 FILE_ATTRIBUTE_READONLY,
1110 if (result == INVALID_HANDLE_VALUE) {
1111 nob_log(
NOB_ERROR,
"Could not open file %s: %s", path, nob_win32_error_message(GetLastError()));
1122 Nob_Fd result = open(path,
1123 O_WRONLY | O_CREAT | O_TRUNC,
1124 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1131 SECURITY_ATTRIBUTES saAttr = {0};
1132 saAttr.nLength =
sizeof(SECURITY_ATTRIBUTES);
1133 saAttr.bInheritHandle = TRUE;
1135 Nob_Fd result = CreateFile(
1141 FILE_ATTRIBUTE_NORMAL,
1145 if (result == INVALID_HANDLE_VALUE) {
1146 nob_log(
NOB_ERROR,
"Could not open file %s: %s", path, nob_win32_error_message(GetLastError()));
1165 bool success =
true;
1166 for (
size_t i = 0; i < procs.
count; ++i) {
1184 DWORD result = WaitForSingleObject(
1189 if (result == WAIT_FAILED) {
1190 nob_log(
NOB_ERROR,
"could not wait on child process: %s", nob_win32_error_message(GetLastError()));
1195 if (!GetExitCodeProcess(proc, &exit_status)) {
1196 nob_log(
NOB_ERROR,
"could not get process exit code: %s", nob_win32_error_message(GetLastError()));
1200 if (exit_status != 0) {
1211 if (waitpid(proc, &wstatus, 0) < 0) {
1212 nob_log(
NOB_ERROR,
"could not wait on command (pid %d): %s", proc, strerror(errno));
1216 if (WIFEXITED(wstatus)) {
1217 int exit_status = WEXITSTATUS(wstatus);
1218 if (exit_status != 0) {
1226 if (WIFSIGNALED(wstatus)) {
1227 nob_log(
NOB_ERROR,
"command process was terminated by signal %d", WTERMSIG(wstatus));
1240 if (procs->
count >= max_procs_count) {
1272 if (redirect.
fdin) {
1276 if (redirect.
fdout) {
1280 if (redirect.
fderr) {
1293 fprintf(stderr,
"[INFO] ");
1296 fprintf(stderr,
"[WARNING] ");
1299 fprintf(stderr,
"[ERROR] ");
1307 va_start(args, fmt);
1308 vfprintf(stderr, fmt, args);
1310 fprintf(stderr,
"\n");
1318 dir = opendir(parent);
1321 nob_log(
NOB_ERROR,
"Could not open directory %s: %s", parent, nob_win32_error_message(GetLastError()));
1323 nob_log(
NOB_ERROR,
"Could not open directory %s: %s", parent, strerror(errno));
1329 struct dirent *ent = readdir(dir);
1330 while (ent != NULL) {
1337 nob_log(
NOB_ERROR,
"Could not read directory %s: %s", parent, nob_win32_error_message(GetLastError()));
1339 nob_log(
NOB_ERROR,
"Could not read directory %s: %s", parent, strerror(errno));
1345 if (dir) closedir(dir);
1353 FILE *f = fopen(path,
"wb");
1355 nob_log(
NOB_ERROR,
"Could not open file %s for writing: %s\n", path, strerror(errno));
1365 const char *buf = data;
1367 size_t n = fwrite(buf, 1, size, f);
1369 nob_log(
NOB_ERROR,
"Could not write into file %s: %s\n", path, strerror(errno));
1384 DWORD attr = GetFileAttributesA(path);
1385 if (attr == INVALID_FILE_ATTRIBUTES) {
1386 nob_log(
NOB_ERROR,
"Could not get file attributes of %s: %s", path, nob_win32_error_message(GetLastError()));
1394 struct stat statbuf;
1395 if (lstat(path, &statbuf) < 0) {
1411 if (!DeleteFileA(path)) {
1412 nob_log(
NOB_ERROR,
"Could not delete file %s: %s", path, nob_win32_error_message(GetLastError()));
1417 if (remove(path) < 0) {
1434 if (type < 0)
return false;
1441 for (
size_t i = 0; i < children.
count; ++i) {
1442 if (strcmp(children.
items[i],
".") == 0)
continue;
1443 if (strcmp(children.
items[i],
"..") == 0)
continue;
1491 size_t n = strlen(cstr);
1493 NOB_ASSERT(result != NULL &&
"Increase NOB_TEMP_CAPACITY");
1494 memcpy(result, cstr, n);
1501 size_t word_size =
sizeof(uintptr_t);
1502 size_t size = (requested_size + word_size - 1)/word_size*word_size;
1504 void *result = &nob_temp[nob_temp_size];
1505 nob_temp_size += size;
1512 va_start(args, format);
1513 int n = vsnprintf(NULL, 0, format, args);
1518 NOB_ASSERT(result != NULL &&
"Extend the size of the temporary allocator");
1520 va_start(args, format);
1521 vsnprintf(result, n + 1, format, args);
1534 return nob_temp_size;
1539 nob_temp_size = checkpoint;
1545 NOB_ASSERT(result != NULL &&
"Extend the size of the temporary allocator");
1547 result[sv.
count] =
'\0';
1556 HANDLE output_path_fd = CreateFile(output_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
1557 if (output_path_fd == INVALID_HANDLE_VALUE) {
1559 if (GetLastError() == ERROR_FILE_NOT_FOUND)
return 1;
1560 nob_log(
NOB_ERROR,
"Could not open file %s: %s", output_path, nob_win32_error_message(GetLastError()));
1563 FILETIME output_path_time;
1564 bSuccess = GetFileTime(output_path_fd, NULL, NULL, &output_path_time);
1565 CloseHandle(output_path_fd);
1567 nob_log(
NOB_ERROR,
"Could not get time of %s: %s", output_path, nob_win32_error_message(GetLastError()));
1571 for (
size_t i = 0; i < input_paths_count; ++i) {
1572 const char *input_path = input_paths[i];
1573 HANDLE input_path_fd = CreateFile(input_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
1574 if (input_path_fd == INVALID_HANDLE_VALUE) {
1576 nob_log(
NOB_ERROR,
"Could not open file %s: %s", input_path, nob_win32_error_message(GetLastError()));
1579 FILETIME input_path_time;
1580 bSuccess = GetFileTime(input_path_fd, NULL, NULL, &input_path_time);
1581 CloseHandle(input_path_fd);
1583 nob_log(
NOB_ERROR,
"Could not get time of %s: %s", input_path, nob_win32_error_message(GetLastError()));
1588 if (CompareFileTime(&input_path_time, &output_path_time) == 1)
return 1;
1593 struct stat statbuf = {0};
1595 if (stat(output_path, &statbuf) < 0) {
1597 if (errno == ENOENT)
return 1;
1601 int output_path_time = statbuf.st_mtime;
1603 for (
size_t i = 0; i < input_paths_count; ++i) {
1604 const char *input_path = input_paths[i];
1605 if (stat(input_path, &statbuf) < 0) {
1610 int input_path_time = statbuf.st_mtime;
1612 if (input_path_time > output_path_time)
return 1;
1627 const char *p1 = strrchr(path,
'/');
1628 const char *p2 = strrchr(path,
'\\');
1629 const char *p = (p1 > p2)? p1 : p2;
1630 return p ? p + 1 : path;
1632 const char *p = strrchr(path,
'/');
1633 return p ? p + 1 : path;
1641 if (!MoveFileEx(old_path, new_path, MOVEFILE_REPLACE_EXISTING)) {
1642 nob_log(
NOB_ERROR,
"could not rename %s to %s: %s", old_path, new_path, nob_win32_error_message(GetLastError()));
1646 if (rename(old_path, new_path) < 0) {
1647 nob_log(
NOB_ERROR,
"could not rename %s to %s: %s", old_path, new_path, strerror(errno));
1658 FILE *f = fopen(path,
"rb");
1664 long long m = _ftelli64(f);
1669 size_t new_count = sb->
count + m;
1681 sb->
count = new_count;
1684 if (!result)
nob_log(
NOB_ERROR,
"Could not read file %s: %s", path, strerror(errno));
1693 va_start(args, fmt);
1694 int n = vsnprintf(NULL, 0, fmt, args);
1702 va_start(args, fmt);
1703 vsnprintf(dest, n+1, fmt, args);
1714 while (i < sv->count && sv->
data[i] != delim) {
1720 if (i < sv->count) {
1733 if (n > sv->
count) {
1756 while (i < sv.
count && isspace(sv.
data[i])) {
1785 if (a.count != b.
count) {
1788 return memcmp(a.data, b.
data, a.count) == 0;
1794 size_t cstr_count = strlen(cstr);
1795 if (sv.
count >= cstr_count) {
1796 size_t ending_start = sv.
count - cstr_count;
1808 return nob_sv_eq(expected_prefix, actual_prefix);
1822 DWORD dwAttrib = GetFileAttributesA(file_path);
1823 return dwAttrib != INVALID_FILE_ATTRIBUTES;
1825 struct stat statbuf;
1826 if (stat(file_path, &statbuf) < 0) {
1827 if (errno == ENOENT)
return 0;
1828 nob_log(
NOB_ERROR,
"Could not check if file %s exists: %s", file_path, strerror(errno));
1838 DWORD nBufferLength = GetCurrentDirectory(0, NULL);
1839 if (nBufferLength == 0) {
1840 nob_log(
NOB_ERROR,
"could not get current directory: %s", nob_win32_error_message(GetLastError()));
1845 if (GetCurrentDirectory(nBufferLength, buffer) == 0) {
1846 nob_log(
NOB_ERROR,
"could not get current directory: %s", nob_win32_error_message(GetLastError()));
1853 if (getcwd(buffer, PATH_MAX) == NULL) {
1854 nob_log(
NOB_ERROR,
"could not get current directory: %s", strerror(errno));
1865 if (!SetCurrentDirectory(path)) {
1866 nob_log(
NOB_ERROR,
"could not set current directory to %s: %s", path, nob_win32_error_message(GetLastError()));
1871 if (chdir(path) < 0) {
1872 nob_log(
NOB_ERROR,
"could not set current directory to %s: %s", path, strerror(errno));
1880#if defined(_WIN32) && !defined(NOB_NO_MINIRENT)
1884 WIN32_FIND_DATA data;
1885 struct dirent *dirent;
1888NOBDEF DIR *opendir(
const char *dirpath)
1892 char buffer[MAX_PATH];
1893 snprintf(buffer, MAX_PATH,
"%s\\*", dirpath);
1896 memset(dir, 0,
sizeof(DIR));
1898 dir->hFind = FindFirstFile(buffer, &dir->data);
1899 if (dir->hFind == INVALID_HANDLE_VALUE) {
1916NOBDEF struct dirent *readdir(DIR *dirp)
1920 if (dirp->dirent == NULL) {
1921 dirp->dirent = (
struct dirent*)
NOB_REALLOC(NULL,
sizeof(
struct dirent));
1922 memset(dirp->dirent, 0,
sizeof(
struct dirent));
1924 if(!FindNextFile(dirp->hFind, &dirp->data)) {
1925 if (GetLastError() != ERROR_NO_MORE_FILES) {
1935 memset(dirp->dirent->d_name, 0,
sizeof(dirp->dirent->d_name));
1938 dirp->dirent->d_name,
1939 dirp->data.cFileName,
1940 sizeof(dirp->dirent->d_name) - 1);
1942 return dirp->dirent;
1945NOBDEF int closedir(DIR *dirp)
1949 if(!FindClose(dirp->hFind)) {
1968#ifndef NOB_STRIP_PREFIX_GUARD_
1969#define NOB_STRIP_PREFIX_GUARD_
1976 #ifdef NOB_STRIP_PREFIX
1977 #define TODO NOB_TODO
1978 #define UNREACHABLE NOB_UNREACHABLE
1979 #define UNUSED NOB_UNUSED
1980 #define ARRAY_LEN NOB_ARRAY_LEN
1981 #define ARRAY_GET NOB_ARRAY_GET
1982 #define INFO NOB_INFO
1983 #define WARNING NOB_WARNING
1984 #define ERROR NOB_ERROR
1985 #define NO_LOGS NOB_NO_LOGS
1986 #define Log_Level Nob_Log_Level
1987 #define minimal_log_level nob_minimal_log_level
1991 #define shift nob_shift
1992 #define shift_args nob_shift_args
1993 #define File_Paths Nob_File_Paths
1994 #define FILE_REGULAR NOB_FILE_REGULAR
1995 #define FILE_DIRECTORY NOB_FILE_DIRECTORY
1996 #define FILE_SYMLINK NOB_FILE_SYMLINK
1997 #define FILE_OTHER NOB_FILE_OTHER
1998 #define File_Type Nob_File_Type
1999 #define mkdir_if_not_exists nob_mkdir_if_not_exists
2000 #define copy_file nob_copy_file
2001 #define copy_directory_recursively nob_copy_directory_recursively
2002 #define read_entire_dir nob_read_entire_dir
2003 #define write_entire_file nob_write_entire_file
2004 #define get_file_type nob_get_file_type
2005 #define delete_file nob_delete_file
2006 #define return_defer nob_return_defer
2007 #define da_append nob_da_append
2008 #define da_free nob_da_free
2009 #define da_append_many nob_da_append_many
2010 #define da_resize nob_da_resize
2011 #define da_reserve nob_da_reserve
2012 #define da_last nob_da_last
2013 #define da_remove_unordered nob_da_remove_unordered
2014 #define da_foreach nob_da_foreach
2015 #define String_Builder Nob_String_Builder
2016 #define read_entire_file nob_read_entire_file
2017 #define sb_appendf nob_sb_appendf
2018 #define sb_append_buf nob_sb_append_buf
2019 #define sb_append_cstr nob_sb_append_cstr
2020 #define sb_append_null nob_sb_append_null
2021 #define sb_free nob_sb_free
2022 #define Proc Nob_Proc
2023 #define INVALID_PROC NOB_INVALID_PROC
2025 #define INVALID_FD NOB_INVALID_FD
2026 #define fd_open_for_read nob_fd_open_for_read
2027 #define fd_open_for_write nob_fd_open_for_write
2028 #define fd_close nob_fd_close
2029 #define Procs Nob_Procs
2030 #define proc_wait nob_proc_wait
2031 #define procs_wait nob_procs_wait
2032 #define procs_wait_and_reset nob_procs_wait_and_reset
2033 #define procs_append_with_flush nob_procs_append_with_flush
2035 #define Cmd_Redirect Nob_Cmd_Redirect
2036 #define cmd_render nob_cmd_render
2037 #define cmd_append nob_cmd_append
2038 #define cmd_extend nob_cmd_extend
2039 #define cmd_free nob_cmd_free
2040 #define cmd_run_async nob_cmd_run_async
2041 #define cmd_run_async_and_reset nob_cmd_run_async_and_reset
2042 #define cmd_run_async_redirect nob_cmd_run_async_redirect
2043 #define cmd_run_async_redirect_and_reset nob_cmd_run_async_redirect_and_reset
2044 #define cmd_run_sync nob_cmd_run_sync
2045 #define cmd_run_sync_and_reset nob_cmd_run_sync_and_reset
2046 #define cmd_run_sync_redirect nob_cmd_run_sync_redirect
2047 #define cmd_run_sync_redirect_and_reset nob_cmd_run_sync_redirect_and_reset
2048 #define temp_strdup nob_temp_strdup
2049 #define temp_alloc nob_temp_alloc
2050 #define temp_sprintf nob_temp_sprintf
2051 #define temp_reset nob_temp_reset
2052 #define temp_save nob_temp_save
2053 #define temp_rewind nob_temp_rewind
2054 #define path_name nob_path_name
2057 #define needs_rebuild nob_needs_rebuild
2058 #define needs_rebuild1 nob_needs_rebuild1
2059 #define file_exists nob_file_exists
2060 #define get_current_dir_temp nob_get_current_dir_temp
2061 #define set_current_dir nob_set_current_dir
2062 #define String_View Nob_String_View
2063 #define temp_sv_to_cstr nob_temp_sv_to_cstr
2064 #define sv_chop_by_delim nob_sv_chop_by_delim
2065 #define sv_chop_left nob_sv_chop_left
2066 #define sv_trim nob_sv_trim
2067 #define sv_trim_left nob_sv_trim_left
2068 #define sv_trim_right nob_sv_trim_right
2069 #define sv_eq nob_sv_eq
2070 #define sv_starts_with nob_sv_starts_with
2071 #define sv_end_with nob_sv_end_with
2072 #define sv_from_cstr nob_sv_from_cstr
2073 #define sv_from_parts nob_sv_from_parts
2074 #define sb_to_sv nob_sb_to_sv
2075 #define win32_error_message nob_win32_error_message
NOBDEF bool nob_sv_end_with(Nob_String_View sv, const char *cstr)
#define nob_da_free(da)
Definition nob.h:317
#define nob_shift(xs, xs_sz)
Definition nob.h:261
#define nob_cmd_append(cmd,...)
Definition nob.h:455
NOBDEF bool nob_cmd_run_sync_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect)
NOBDEF Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n)
NOBDEF bool nob_procs_wait_and_reset(Nob_Procs *procs)
NOBDEF bool nob_set_current_dir(const char *path)
#define nob_sb_append_cstr(sb, cstr)
Definition nob.h:377
#define NOB_REBUILD_URSELF(binary_path, source_path)
Definition nob.h:583
NOBDEF int nob_file_exists(const char *file_path)
int Nob_Proc
Definition nob.h:398
#define NOB_FREE
Definition nob.h:191
NOBDEF Nob_Fd nob_fd_open_for_read(const char *path)
NOBDEF bool nob_delete_file(const char *path)
NOBDEF void nob__go_rebuild_urself(int argc, char **argv, const char *source_path,...)
NOBDEF bool nob_rename(const char *old_path, const char *new_path)
NOBDEF bool nob_copy_directory_recursively(const char *src_path, const char *dst_path)
NOBDEF int nob_needs_rebuild1(const char *output_path, const char *input_path)
NOBDEF bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children)
#define nob_da_reserve(da, expected_capacity)
Definition nob.h:296
NOBDEF void nob_fd_close(Nob_Fd fd)
NOBDEF char * nob_temp_strdup(const char *cstr)
NOBDEF bool nob_cmd_run_sync_and_reset(Nob_Cmd *cmd)
#define NOB_INVALID_FD
Definition nob.h:401
NOBDEF bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix)
NOBDEF void nob_log(Nob_Log_Level level, const char *fmt,...) NOB_PRINTF_FORMAT(2
NOBDEF Nob_Proc nob_cmd_run_async_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect)
#define NOB_INVALID_PROC
Definition nob.h:399
NOBDEF Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim)
NOBDEF bool nob_proc_wait(Nob_Proc proc)
#define NOB_UNREACHABLE(message)
Definition nob.h:241
NOBDEF bool nob_procs_wait(Nob_Procs procs)
NOBDEF char NOBDEF void nob_temp_reset(void)
NOBDEF bool nob_write_entire_file(const char *path, const void *data, size_t size)
int Nob_Fd
Definition nob.h:400
NOBDEF char * nob_temp_sprintf(const char *format,...) NOB_PRINTF_FORMAT(1
NOBDEF Nob_String_View nob_sv_trim_right(Nob_String_View sv)
NOBDEF bool nob_cmd_run_sync_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect)
#define NOB_TEMP_CAPACITY
Definition nob.h:487
NOBDEF Nob_String_View nob_sv_from_cstr(const char *cstr)
NOBDEF bool nob_mkdir_if_not_exists(const char *path)
#define nob_return_defer(value)
Definition nob.h:289
NOBDEF bool nob_cmd_run_sync(Nob_Cmd cmd)
NOBDEF const char * nob_temp_sv_to_cstr(Nob_String_View sv)
#define nob_sb_free(sb)
Definition nob.h:389
Nob_File_Type
Definition nob.h:274
@ NOB_FILE_SYMLINK
Definition nob.h:277
@ NOB_FILE_DIRECTORY
Definition nob.h:276
@ NOB_FILE_REGULAR
Definition nob.h:275
@ NOB_FILE_OTHER
Definition nob.h:278
NOBDEF void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render)
NOBDEF int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count)
#define nob_da_append_many(da, new_items, new_items_count)
Definition nob.h:320
NOBDEF const char * nob_get_current_dir_temp(void)
Nob_Log_Level
Definition nob.h:247
@ NOB_WARNING
Definition nob.h:249
@ NOB_ERROR
Definition nob.h:250
@ NOB_NO_LOGS
Definition nob.h:251
@ NOB_INFO
Definition nob.h:248
#define nob_cmd_run_async(cmd)
Definition nob.h:467
#define NOB_REALLOC
Definition nob.h:186
#define NOBDEF
Definition nob.h:176
NOBDEF bool nob_sv_eq(Nob_String_View a, Nob_String_View b)
NOBDEF int nob_sb_appendf(Nob_String_Builder *sb, const char *fmt,...) NOB_PRINTF_FORMAT(2
NOBDEF Nob_File_Type nob_get_file_type(const char *path)
NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count)
#define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK)
Definition nob.h:236
NOBDEF const char * nob_path_name(const char *path)
#define NOB_ASSERT
Definition nob.h:181
NOBDEF Nob_Proc nob_cmd_run_async_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect)
NOBDEF Nob_Fd nob_fd_open_for_write(const char *path)
NOBDEF bool nob_copy_file(const char *src_path, const char *dst_path)
NOBDEF size_t nob_temp_save(void)
#define nob_sb_append_null(sb)
Definition nob.h:386
NOBDEF Nob_String_View nob_sv_trim_left(Nob_String_View sv)
#define nob_da_append(da, item)
Definition nob.h:311
NOBDEF void nob_temp_rewind(size_t checkpoint)
Nob_Log_Level nob_minimal_log_level
NOBDEF bool nob_procs_append_with_flush(Nob_Procs *procs, Nob_Proc proc, size_t max_procs_count)
NOBDEF bool nob_read_entire_file(const char *path, Nob_String_Builder *sb)
NOBDEF Nob_String_View nob_sv_trim(Nob_String_View sv)
NOBDEF void * nob_temp_alloc(size_t size)
NOBDEF Nob_Proc nob_cmd_run_async_and_reset(Nob_Cmd *cmd)
Nob_Fd * fdout
Definition nob.h:445
Nob_Fd * fderr
Definition nob.h:446
Nob_Fd * fdin
Definition nob.h:444
size_t capacity
Definition nob.h:427
size_t count
Definition nob.h:426
const char ** items
Definition nob.h:425
size_t capacity
Definition nob.h:271
const char ** items
Definition nob.h:269
size_t count
Definition nob.h:270
size_t count
Definition nob.h:410
Nob_Proc * items
Definition nob.h:409
size_t capacity
Definition nob.h:411
size_t count
Definition nob.h:366
char * items
Definition nob.h:365
size_t capacity
Definition nob.h:367
size_t count
Definition nob.h:629
const char * data
Definition nob.h:630