#include #include #include #include #include #include #include #include #include #include enum class Color { black, red, green, yellow, blue, purple, cyan, white, reset, }; void pick_color(Color color) { switch (color) { case Color::black: printf("\033[0;30m"); break; case Color::red: printf("\033[0;31m"); break; case Color::green: printf("\033[0;32m"); break; case Color::yellow: printf("\033[0;33m"); break; case Color::blue: printf("\033[0;34m"); break; case Color::purple: printf("\033[0;35m"); break; case Color::cyan: printf("\033[0;36m"); break; case Color::white: printf("\033[0;37m"); break; case Color::reset: printf("\033[0m"); break; default: break; } } void print_command(std::vector &arguments) { pick_color(Color::cyan); for (auto &&i : arguments) { printf("%s ", i.c_str()); } pick_color(Color::white); printf("\n"); } int nob_cmd_run_async(std::vector &arguments) { std::vector argument_list; for (const auto &arg : arguments) { argument_list.push_back(const_cast(arg.c_str())); } argument_list.push_back(NULL); pid_t cpid = fork(); if (cpid < 0) { printf("Could not fork child process: %s\n", strerror(errno)); return -1; } if (cpid == 0) { if (execvp(argument_list[0], argument_list.data()) < 0) { print_command(arguments); printf("Could not exec child process: %s\n", strerror(errno)); exit(1); } assert(0 && "unreachable"); } return cpid; } bool nob_proc_wait(int proc) { if (proc == -1) return false; for (;;) { int wstatus = 0; if (waitpid(proc, &wstatus, 0) < 0) { printf("could not wait on command (pid %d): %s\n", proc, strerror(errno)); return false; } if (WIFEXITED(wstatus)) { int exit_status = WEXITSTATUS(wstatus); if (exit_status != 0) { printf("command exited with exit code %d\n", exit_status); return false; } break; } if (WIFSIGNALED(wstatus)) { printf("command process was terminated by %s\n", strsignal(WTERMSIG(wstatus))); return false; } } return true; } bool nob_cmd_run_sync(std::vector &arguments) { print_command(arguments); int p = nob_cmd_run_async(arguments); if (p == -1) return false; return nob_proc_wait(p); } bool check_if_rebuild(std::filesystem::path &org_path, std::filesystem::path &new_path) { struct stat file_stat_one; if (stat(org_path.c_str(), &file_stat_one)) return false; struct stat file_stat_two; if (stat(new_path.c_str(), &file_stat_two)) return true; return file_stat_one.st_ctime > file_stat_two.st_ctime; } bool rebuild_my_self(std::filesystem::path src_path, int argc, const char **exec_path) { std::vector input; for (int i = 0; i < argc; ++i) input.push_back(exec_path[i]); std::filesystem::path exec = input[0]; if (!check_if_rebuild(src_path, exec)) return false; std::vector comand = {"g++", src_path, "-o", exec_path[0], "-g"}; if (!nob_cmd_run_sync(comand)) return false; if (!nob_cmd_run_sync(input)) return false; printf("rebuild\n"); return true; } struct nob_directory { std::vector files; std::vector dirs; }; nob_directory get_all_files_in_dir(std::filesystem::path directory_path) { namespace fs = std::filesystem; nob_directory dir; if (!fs::is_directory(directory_path)) return dir; std::list dirs; dirs.push_back(directory_path); dir.dirs.push_back(directory_path); while (!dirs.empty()) { for (const auto &entry : fs::directory_iterator(dirs.front())) { // Check if the entry is a regular file if (fs::is_regular_file(entry)) { dir.files.push_back(entry.path()); } // Check if the entry is a directory else if (fs::is_directory(entry)) { dirs.push_back(entry.path()); dir.dirs.push_back(entry.path()); } } dirs.pop_front(); } return dir; }