nob.h 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163
  1. /* nob - v1.20.6 - Public Domain - https://github.com/tsoding/nob.h
  2. This library is the next generation of the [NoBuild](https://github.com/tsoding/nobuild) idea.
  3. # Quick Example
  4. ```c
  5. // nob.c
  6. #define NOB_IMPLEMENTATION
  7. #include "nob.h"
  8. int main(int argc, char **argv)
  9. {
  10. NOB_GO_REBUILD_URSELF(argc, argv);
  11. Nob_Cmd cmd = {0};
  12. nob_cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c");
  13. if (!nob_cmd_run_sync(cmd)) return 1;
  14. return 0;
  15. }
  16. ```
  17. ```console
  18. $ cc -o nob nob.c
  19. $ ./nob
  20. ```
  21. The `nob` automatically rebuilds itself if `nob.c` is modified thanks to
  22. the `NOB_GO_REBUILD_URSELF` macro (don't forget to check out how it works below)
  23. # The Zoo of `nob_cmd_run_*` Functions
  24. `Nob_Cmd` is just a dynamic array of strings which represents a command and its arguments.
  25. First you append the arguments
  26. ```c
  27. Nob_Cmd cmd = {0};
  28. nob_cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c");
  29. ```
  30. Then you run it
  31. ```c
  32. if (!nob_cmd_run_sync(cmd)) return 1;
  33. ```
  34. `*_sync` at the end indicates that the function blocks until the command finishes executing
  35. and returns `true` on success and `false` on failure. You can run the command asynchronously
  36. but you have to explitictly wait for it afterwards:
  37. ```c
  38. Nob_Proc p = nob_cmd_run_async(cmd);
  39. if (p == NOB_INVALID_PROC) return 1;
  40. if (!nob_proc_wait(p)) return 1;
  41. ```
  42. One of the problems with running commands like that is that `Nob_Cmd` still contains the arguments
  43. from the previously run command. If you want to reuse the same `Nob_Cmd` you have to not forget to reset
  44. it
  45. ```c
  46. Nob_Cmd cmd = {0};
  47. nob_cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c");
  48. if (!nob_cmd_run_sync(cmd)) return 1;
  49. cmd.count = 0;
  50. nob_cmd_append(&cmd, "./main", "foo", "bar", "baz");
  51. if (!nob_cmd_run_sync(cmd)) return 1;
  52. cmd.count = 0;
  53. ```
  54. Which is a bit error prone. To make it a bit easier we have `nob_cmd_run_sync_and_reset()` which
  55. accepts `Nob_Cmd` by reference and resets it for you:
  56. ```c
  57. Nob_Cmd cmd = {0};
  58. nob_cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c");
  59. if (!nob_cmd_run_sync_and_reset(&cmd)) return 1;
  60. nob_cmd_append(&cmd, "./main", "foo", "bar", "baz");
  61. if (!nob_cmd_run_sync_and_reset(&cmd)) return 1;
  62. ```
  63. There is of course also `nob_cmd_run_async_and_reset()` to maintain the pattern.
  64. The stdin, stdout and stderr of any command can be redirected by using `Nob_Cmd_Redirect` structure
  65. along with `nob_cmd_run_sync_redirect()` or `nob_cmd_run_async_redirect()`
  66. ```c
  67. // Opening all the necessary files
  68. Nob_Fd fdin = nob_fd_open_for_read("input.txt");
  69. if (fdin == NOB_INVALID_FD) return 1;
  70. Nob_Fd fdout = nob_fd_open_for_write("output.txt");
  71. if (fdout == NOB_INVALID_FD) return 1;
  72. Nob_Fd fderr = nob_fd_open_for_write("error.txt");
  73. if (fderr == NOB_INVALID_FD) return 1;
  74. // Preparing the command
  75. Nob_Cmd cmd = {0};
  76. nob_cmd_append(&cmd, "./main", "foo", "bar", "baz");
  77. // Running the command synchronously redirecting the standard streams
  78. bool ok = nob_cmd_run_sync_redirect(cmd, (Nob_Cmd_Redirect) {
  79. .fdin = fdin,
  80. .fdout = fdout,
  81. .fderr = fderr,
  82. });
  83. if (!ok) return 1;
  84. // Closing all the files
  85. nob_fd_close(fdin);
  86. nob_fd_close(fdout);
  87. nob_fd_close(fderr);
  88. // Reseting the command
  89. cmd.count = 0;
  90. ```
  91. And of course if you find closing the files and reseting the command annoying we have
  92. `nob_cmd_run_sync_redirect_and_reset()` and `nob_cmd_run_async_redirect_and_reset()`
  93. which do all of that for you automatically.
  94. All the Zoo of `nob_cmd_run_*` functions follows the same pattern: sync/async,
  95. redirect/no redirect, and_reset/no and_reset. They always come in that order.
  96. # Stripping off `nob_` Prefixes
  97. Since Pure C does not have any namespaces we prefix each name of the API with the `nob_` to avoid any
  98. potential conflicts with any other names in your code. But sometimes it is very annoying and makes
  99. the code noisy. If you know that none of the names from nob.h conflict with anything in your code
  100. you can enable NOB_STRIP_PREFIX macro and just drop all the prefixes:
  101. ```c
  102. // nob.c
  103. #define NOB_IMPLEMENTATION
  104. #define NOB_STRIP_PREFIX
  105. #include "nob.h"
  106. int main(int argc, char **argv)
  107. {
  108. NOB_GO_REBUILD_URSELF(argc, argv);
  109. Cmd cmd = {0};
  110. cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c");
  111. if (!cmd_run_sync(cmd)) return 1;
  112. return 0;
  113. }
  114. ```
  115. Not all the names have strippable prefixes. All the redefinable names like `NOB_GO_REBUILD_URSELF`
  116. for instance will retain their prefix even if NOB_STRIP_PREFIX is enabled. Notable exception is the
  117. nob_log() function. Stripping away the prefix results in log() which was historically always referring
  118. to the natural logarithmic function that is already defined in math.h. So there is no reason to strip
  119. off the prefix for nob_log(). Another exception is nob_rename() which collides with the widely known
  120. POSIX function rename(2) if you strip the prefix off.
  121. The prefixes are stripped off only on the level of preprocessor. The names of the functions in the
  122. compiled object file will still retain the `nob_` prefix. Keep that in mind when you FFI with nob.h
  123. from other languages (for whatever reason).
  124. If only few specific names create conflicts for you, you can just #undef those names after the
  125. `#include <nob.h>` since they are macros anyway.
  126. */
  127. #ifndef NOB_H_
  128. #define NOB_H_
  129. #ifndef NOB_ASSERT
  130. #include <assert.h>
  131. #define NOB_ASSERT assert
  132. #endif /* NOB_ASSERT */
  133. #ifndef NOB_REALLOC
  134. #include <stdlib.h>
  135. #define NOB_REALLOC realloc
  136. #endif /* NOB_REALLOC */
  137. #ifndef NOB_FREE
  138. #include <stdlib.h>
  139. #define NOB_FREE free
  140. #endif /* NOB_FREE */
  141. #include <stdbool.h>
  142. #include <stdlib.h>
  143. #include <stdio.h>
  144. #include <stdarg.h>
  145. #include <string.h>
  146. #include <errno.h>
  147. #include <ctype.h>
  148. #include <limits.h>
  149. #ifdef _WIN32
  150. # define WIN32_LEAN_AND_MEAN
  151. # define _WINUSER_
  152. # define _WINGDI_
  153. # define _IMM_
  154. # define _WINCON_
  155. # include <windows.h>
  156. # include <direct.h>
  157. # include <shellapi.h>
  158. #else
  159. # include <sys/types.h>
  160. # include <sys/wait.h>
  161. # include <sys/stat.h>
  162. # include <unistd.h>
  163. # include <fcntl.h>
  164. #endif
  165. #ifdef _WIN32
  166. # define NOB_LINE_END "\r\n"
  167. #else
  168. # define NOB_LINE_END "\n"
  169. #endif
  170. #if defined(__GNUC__) || defined(__clang__)
  171. // https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
  172. # ifdef __MINGW_PRINTF_FORMAT
  173. # define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (__MINGW_PRINTF_FORMAT, STRING_INDEX, FIRST_TO_CHECK)))
  174. # else
  175. # define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (printf, STRING_INDEX, FIRST_TO_CHECK)))
  176. # endif // __MINGW_PRINTF_FORMAT
  177. #else
  178. // TODO: implement NOB_PRINTF_FORMAT for MSVC
  179. # define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK)
  180. #endif
  181. #define NOB_UNUSED(value) (void)(value)
  182. #define NOB_TODO(message) do { fprintf(stderr, "%s:%d: TODO: %s\n", __FILE__, __LINE__, message); abort(); } while(0)
  183. #define NOB_UNREACHABLE(message) do { fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); abort(); } while(0)
  184. #define NOB_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
  185. #define NOB_ARRAY_GET(array, index) \
  186. (NOB_ASSERT((size_t)index < NOB_ARRAY_LEN(array)), array[(size_t)index])
  187. typedef enum {
  188. NOB_INFO,
  189. NOB_WARNING,
  190. NOB_ERROR,
  191. NOB_NO_LOGS,
  192. } Nob_Log_Level;
  193. // Any messages with the level below nob_minimal_log_level are going to be suppressed.
  194. extern Nob_Log_Level nob_minimal_log_level;
  195. void nob_log(Nob_Log_Level level, const char *fmt, ...) NOB_PRINTF_FORMAT(2, 3);
  196. // It is an equivalent of shift command from bash. It basically pops an element from
  197. // the beginning of a sized array.
  198. #define nob_shift(xs, xs_sz) (NOB_ASSERT((xs_sz) > 0), (xs_sz)--, *(xs)++)
  199. // NOTE: nob_shift_args() is an alias for an old variant of nob_shift that only worked with
  200. // the command line arguments passed to the main() function. nob_shift() is more generic.
  201. // So nob_shift_args() is semi-deprecated, but I don't see much reason to urgently
  202. // remove it. This alias does not hurt anybody.
  203. #define nob_shift_args(argc, argv) nob_shift(*argv, *argc)
  204. typedef struct {
  205. const char **items;
  206. size_t count;
  207. size_t capacity;
  208. } Nob_File_Paths;
  209. typedef enum {
  210. NOB_FILE_REGULAR = 0,
  211. NOB_FILE_DIRECTORY,
  212. NOB_FILE_SYMLINK,
  213. NOB_FILE_OTHER,
  214. } Nob_File_Type;
  215. bool nob_mkdir_if_not_exists(const char *path);
  216. bool nob_copy_file(const char *src_path, const char *dst_path);
  217. bool nob_copy_directory_recursively(const char *src_path, const char *dst_path);
  218. bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children);
  219. bool nob_write_entire_file(const char *path, const void *data, size_t size);
  220. Nob_File_Type nob_get_file_type(const char *path);
  221. bool nob_delete_file(const char *path);
  222. #define nob_return_defer(value) do { result = (value); goto defer; } while(0)
  223. // Initial capacity of a dynamic array
  224. #ifndef NOB_DA_INIT_CAP
  225. #define NOB_DA_INIT_CAP 256
  226. #endif
  227. #define nob_da_reserve(da, expected_capacity) \
  228. do { \
  229. if ((expected_capacity) > (da)->capacity) { \
  230. if ((da)->capacity == 0) { \
  231. (da)->capacity = NOB_DA_INIT_CAP; \
  232. } \
  233. while ((expected_capacity) > (da)->capacity) { \
  234. (da)->capacity *= 2; \
  235. } \
  236. (da)->items = NOB_REALLOC((da)->items, (da)->capacity * sizeof(*(da)->items)); \
  237. NOB_ASSERT((da)->items != NULL && "Buy more RAM lol"); \
  238. } \
  239. } while (0)
  240. // Append an item to a dynamic array
  241. #define nob_da_append(da, item) \
  242. do { \
  243. nob_da_reserve((da), (da)->count + 1); \
  244. (da)->items[(da)->count++] = (item); \
  245. } while (0)
  246. #define nob_da_free(da) NOB_FREE((da).items)
  247. // Append several items to a dynamic array
  248. #define nob_da_append_many(da, new_items, new_items_count) \
  249. do { \
  250. nob_da_reserve((da), (da)->count + (new_items_count)); \
  251. memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
  252. (da)->count += (new_items_count); \
  253. } while (0)
  254. #define nob_da_resize(da, new_size) \
  255. do { \
  256. nob_da_reserve((da), new_size); \
  257. (da)->count = (new_size); \
  258. } while (0)
  259. #define nob_da_last(da) (da)->items[(NOB_ASSERT((da)->count > 0), (da)->count-1)]
  260. #define nob_da_remove_unordered(da, i) \
  261. do { \
  262. size_t j = (i); \
  263. NOB_ASSERT(j < (da)->count); \
  264. (da)->items[j] = (da)->items[--(da)->count]; \
  265. } while(0)
  266. // Foreach over Dynamic Arrays. Example:
  267. // ```c
  268. // typedef struct {
  269. // int *items;
  270. // size_t count;
  271. // size_t capacity;
  272. // } Numbers;
  273. //
  274. // Numbers xs = {0};
  275. //
  276. // nob_da_append(&xs, 69);
  277. // nob_da_append(&xs, 420);
  278. // nob_da_append(&xs, 1337);
  279. //
  280. // nob_da_foreach(int, x, &xs) {
  281. // // `x` here is a pointer to the current element. You can get its index by taking a difference
  282. // // between `x` and the start of the array which is `x.items`.
  283. // size_t index = x - xs.items;
  284. // nob_log(INFO, "%zu: %d", index, *x);
  285. // }
  286. // ```
  287. #define nob_da_foreach(Type, it, da) for (Type *it = (da)->items; it < (da)->items + (da)->count; ++it)
  288. typedef struct {
  289. char *items;
  290. size_t count;
  291. size_t capacity;
  292. } Nob_String_Builder;
  293. bool nob_read_entire_file(const char *path, Nob_String_Builder *sb);
  294. int nob_sb_appendf(Nob_String_Builder *sb, const char *fmt, ...) NOB_PRINTF_FORMAT(2, 3);
  295. // Append a sized buffer to a string builder
  296. #define nob_sb_append_buf(sb, buf, size) nob_da_append_many(sb, buf, size)
  297. // Append a NULL-terminated string to a string builder
  298. #define nob_sb_append_cstr(sb, cstr) \
  299. do { \
  300. const char *s = (cstr); \
  301. size_t n = strlen(s); \
  302. nob_da_append_many(sb, s, n); \
  303. } while (0)
  304. // Append a single NULL character at the end of a string builder. So then you can
  305. // use it a NULL-terminated C string
  306. #define nob_sb_append_null(sb) nob_da_append_many(sb, "", 1)
  307. // Free the memory allocated by a string builder
  308. #define nob_sb_free(sb) NOB_FREE((sb).items)
  309. // Process handle
  310. #ifdef _WIN32
  311. typedef HANDLE Nob_Proc;
  312. #define NOB_INVALID_PROC INVALID_HANDLE_VALUE
  313. typedef HANDLE Nob_Fd;
  314. #define NOB_INVALID_FD INVALID_HANDLE_VALUE
  315. #else
  316. typedef int Nob_Proc;
  317. #define NOB_INVALID_PROC (-1)
  318. typedef int Nob_Fd;
  319. #define NOB_INVALID_FD (-1)
  320. #endif // _WIN32
  321. Nob_Fd nob_fd_open_for_read(const char *path);
  322. Nob_Fd nob_fd_open_for_write(const char *path);
  323. void nob_fd_close(Nob_Fd fd);
  324. typedef struct {
  325. Nob_Proc *items;
  326. size_t count;
  327. size_t capacity;
  328. } Nob_Procs;
  329. // Wait until the process has finished
  330. bool nob_proc_wait(Nob_Proc proc);
  331. // Wait until all the processes have finished
  332. bool nob_procs_wait(Nob_Procs procs);
  333. // Wait until all the processes have finished and empty the procs array
  334. bool nob_procs_wait_and_reset(Nob_Procs *procs);
  335. // Append a new process to procs array and if procs.count reaches max_procs_count call nob_procs_wait_and_reset() on it
  336. bool nob_procs_append_with_flush(Nob_Procs *procs, Nob_Proc proc, size_t max_procs_count);
  337. // A command - the main workhorse of Nob. Nob is all about building commands and running them
  338. typedef struct {
  339. const char **items;
  340. size_t count;
  341. size_t capacity;
  342. } Nob_Cmd;
  343. // Example:
  344. // ```c
  345. // Nob_Fd fdin = nob_fd_open_for_read("input.txt");
  346. // if (fdin == NOB_INVALID_FD) fail();
  347. // Nob_Fd fdout = nob_fd_open_for_write("output.txt");
  348. // if (fdout == NOB_INVALID_FD) fail();
  349. // Nob_Cmd cmd = {0};
  350. // nob_cmd_append(&cmd, "cat");
  351. // if (!nob_cmd_run_sync_redirect_and_reset(&cmd, (Nob_Cmd_Redirect) {
  352. // .fdin = &fdin,
  353. // .fdout = &fdout
  354. // })) fail();
  355. // ```
  356. typedef struct {
  357. Nob_Fd *fdin;
  358. Nob_Fd *fdout;
  359. Nob_Fd *fderr;
  360. } Nob_Cmd_Redirect;
  361. // Render a string representation of a command into a string builder. Keep in mind the the
  362. // string builder is not NULL-terminated by default. Use nob_sb_append_null if you plan to
  363. // use it as a C string.
  364. void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render);
  365. // TODO: implement C++ support for nob.h
  366. #define nob_cmd_append(cmd, ...) \
  367. nob_da_append_many(cmd, \
  368. ((const char*[]){__VA_ARGS__}), \
  369. (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*)))
  370. #define nob_cmd_extend(cmd, other_cmd) \
  371. nob_da_append_many(cmd, (other_cmd)->items, (other_cmd)->count)
  372. // Free all the memory allocated by command arguments
  373. #define nob_cmd_free(cmd) NOB_FREE(cmd.items)
  374. // Run command asynchronously
  375. #define nob_cmd_run_async(cmd) nob_cmd_run_async_redirect(cmd, (Nob_Cmd_Redirect) {0})
  376. // NOTE: nob_cmd_run_async_and_reset() is just like nob_cmd_run_async() except it also resets cmd.count to 0
  377. // so the Nob_Cmd instance can be seamlessly used several times in a row
  378. Nob_Proc nob_cmd_run_async_and_reset(Nob_Cmd *cmd);
  379. // Run redirected command asynchronously
  380. Nob_Proc nob_cmd_run_async_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect);
  381. // Run redirected command asynchronously and set cmd.count to 0 and close all the opened files
  382. Nob_Proc nob_cmd_run_async_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect);
  383. // Run command synchronously
  384. bool nob_cmd_run_sync(Nob_Cmd cmd);
  385. // NOTE: nob_cmd_run_sync_and_reset() is just like nob_cmd_run_sync() except it also resets cmd.count to 0
  386. // so the Nob_Cmd instance can be seamlessly used several times in a row
  387. bool nob_cmd_run_sync_and_reset(Nob_Cmd *cmd);
  388. // Run redirected command synchronously
  389. bool nob_cmd_run_sync_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect);
  390. // Run redirected command synchronously and set cmd.count to 0 and close all the opened files
  391. bool nob_cmd_run_sync_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect);
  392. #ifndef NOB_TEMP_CAPACITY
  393. #define NOB_TEMP_CAPACITY (8*1024*1024)
  394. #endif // NOB_TEMP_CAPACITY
  395. char *nob_temp_strdup(const char *cstr);
  396. void *nob_temp_alloc(size_t size);
  397. char *nob_temp_sprintf(const char *format, ...) NOB_PRINTF_FORMAT(1, 2);
  398. void nob_temp_reset(void);
  399. size_t nob_temp_save(void);
  400. void nob_temp_rewind(size_t checkpoint);
  401. // Given any path returns the last part of that path.
  402. // "/path/to/a/file.c" -> "file.c"; "/path/to/a/directory" -> "directory"
  403. const char *nob_path_name(const char *path);
  404. bool nob_rename(const char *old_path, const char *new_path);
  405. int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count);
  406. int nob_needs_rebuild1(const char *output_path, const char *input_path);
  407. int nob_file_exists(const char *file_path);
  408. const char *nob_get_current_dir_temp(void);
  409. bool nob_set_current_dir(const char *path);
  410. // TODO: we should probably document somewhere all the compiler we support
  411. // The nob_cc_* macros try to abstract away the specific compiler.
  412. // They are verify basic and not particularly flexible, but you can redefine them if you need to
  413. // or not use them at all and create your own abstraction on top of Nob_Cmd.
  414. #ifndef nob_cc
  415. # if _WIN32
  416. # if defined(__GNUC__)
  417. # define nob_cc(cmd) nob_cmd_append(cmd, "cc")
  418. # elif defined(__clang__)
  419. # define nob_cc(cmd) nob_cmd_append(cmd, "clang")
  420. # elif defined(_MSC_VER)
  421. # define nob_cc(cmd) nob_cmd_append(cmd, "cl.exe")
  422. # endif
  423. # else
  424. # define nob_cc(cmd) nob_cmd_append(cmd, "cc")
  425. # endif
  426. #endif // nob_cc
  427. #ifndef nob_cc_flags
  428. # if defined(_MSC_VER) && !defined(__clang__)
  429. # define nob_cc_flags(...) // TODO: Add some cool recommended flags for MSVC (I don't really know any)
  430. # else
  431. # define nob_cc_flags(cmd) nob_cmd_append(cmd, "-Wall", "-Wextra")
  432. # endif
  433. #endif // nob_cc_output
  434. #ifndef nob_cc_output
  435. # if defined(_MSC_VER) && !defined(__clang__)
  436. # define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, nob_temp_sprintf("/Fe:%s", (output_path)))
  437. # else
  438. # define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, "-o", (output_path))
  439. # endif
  440. #endif // nob_cc_output
  441. #ifndef nob_cc_inputs
  442. # define nob_cc_inputs(cmd, ...) nob_cmd_append(cmd, __VA_ARGS__)
  443. #endif // nob_cc_inputs
  444. // TODO: add MinGW support for Go Rebuild Urself™ Technology and all the nob_cc_* macros above
  445. // Musializer contributors came up with a pretty interesting idea of an optional prefix macro which could be useful for
  446. // MinGW support:
  447. // https://github.com/tsoding/musializer/blob/b7578cc76b9ecb573d239acc9ccf5a04d3aba2c9/src_build/nob_win64_mingw.c#L3-L9
  448. // TODO: Maybe instead NOB_REBUILD_URSELF macro, the Go Rebuild Urself™ Technology should use the
  449. // user defined nob_cc_* macros instead?
  450. #ifndef NOB_REBUILD_URSELF
  451. # if defined(_WIN32)
  452. # if defined(__GNUC__)
  453. # define NOB_REBUILD_URSELF(binary_path, source_path) "gcc", "-o", binary_path, source_path
  454. # elif defined(__clang__)
  455. # define NOB_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
  456. # elif defined(_MSC_VER)
  457. # define NOB_REBUILD_URSELF(binary_path, source_path) "cl.exe", nob_temp_sprintf("/Fe:%s", (binary_path)), source_path
  458. # endif
  459. # else
  460. # define NOB_REBUILD_URSELF(binary_path, source_path) "cc", "-o", binary_path, source_path
  461. # endif
  462. #endif
  463. // Go Rebuild Urself™ Technology
  464. //
  465. // How to use it:
  466. // int main(int argc, char** argv) {
  467. // NOB_GO_REBUILD_URSELF(argc, argv);
  468. // // actual work
  469. // return 0;
  470. // }
  471. //
  472. // After your added this macro every time you run ./nob it will detect
  473. // that you modified its original source code and will try to rebuild itself
  474. // before doing any actual work. So you only need to bootstrap your build system
  475. // once.
  476. //
  477. // The modification is detected by comparing the last modified times of the executable
  478. // and its source code. The same way the make utility usually does it.
  479. //
  480. // The rebuilding is done by using the NOB_REBUILD_URSELF macro which you can redefine
  481. // if you need a special way of bootstraping your build system. (which I personally
  482. // do not recommend since the whole idea of NoBuild is to keep the process of bootstrapping
  483. // as simple as possible and doing all of the actual work inside of ./nob)
  484. //
  485. void nob__go_rebuild_urself(int argc, char **argv, const char *source_path, ...);
  486. #define NOB_GO_REBUILD_URSELF(argc, argv) nob__go_rebuild_urself(argc, argv, __FILE__, NULL)
  487. // Sometimes your nob.c includes additional files, so you want the Go Rebuild Urself™ Technology to check
  488. // if they also were modified and rebuild nob.c accordingly. For that we have NOB_GO_REBUILD_URSELF_PLUS():
  489. // ```c
  490. // #define NOB_IMPLEMENTATION
  491. // #include "nob.h"
  492. //
  493. // #include "foo.c"
  494. // #include "bar.c"
  495. //
  496. // int main(int argc, char **argv)
  497. // {
  498. // NOB_GO_REBUILD_URSELF_PLUS(argc, argv, "foo.c", "bar.c");
  499. // // ...
  500. // return 0;
  501. // }
  502. #define NOB_GO_REBUILD_URSELF_PLUS(argc, argv, ...) nob__go_rebuild_urself(argc, argv, __FILE__, __VA_ARGS__, NULL);
  503. typedef struct {
  504. size_t count;
  505. const char *data;
  506. } Nob_String_View;
  507. const char *nob_temp_sv_to_cstr(Nob_String_View sv);
  508. Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim);
  509. Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n);
  510. Nob_String_View nob_sv_trim(Nob_String_View sv);
  511. Nob_String_View nob_sv_trim_left(Nob_String_View sv);
  512. Nob_String_View nob_sv_trim_right(Nob_String_View sv);
  513. bool nob_sv_eq(Nob_String_View a, Nob_String_View b);
  514. bool nob_sv_end_with(Nob_String_View sv, const char *cstr);
  515. bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix);
  516. Nob_String_View nob_sv_from_cstr(const char *cstr);
  517. Nob_String_View nob_sv_from_parts(const char *data, size_t count);
  518. // nob_sb_to_sv() enables you to just view Nob_String_Builder as Nob_String_View
  519. #define nob_sb_to_sv(sb) nob_sv_from_parts((sb).items, (sb).count)
  520. // printf macros for String_View
  521. #ifndef SV_Fmt
  522. #define SV_Fmt "%.*s"
  523. #endif // SV_Fmt
  524. #ifndef SV_Arg
  525. #define SV_Arg(sv) (int) (sv).count, (sv).data
  526. #endif // SV_Arg
  527. // USAGE:
  528. // String_View name = ...;
  529. // printf("Name: "SV_Fmt"\n", SV_Arg(name));
  530. // minirent.h HEADER BEGIN ////////////////////////////////////////
  531. // Copyright 2021 Alexey Kutepov <[email protected]>
  532. //
  533. // Permission is hereby granted, free of charge, to any person obtaining
  534. // a copy of this software and associated documentation files (the
  535. // "Software"), to deal in the Software without restriction, including
  536. // without limitation the rights to use, copy, modify, merge, publish,
  537. // distribute, sublicense, and/or sell copies of the Software, and to
  538. // permit persons to whom the Software is furnished to do so, subject to
  539. // the following conditions:
  540. //
  541. // The above copyright notice and this permission notice shall be
  542. // included in all copies or substantial portions of the Software.
  543. //
  544. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  545. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  546. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  547. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  548. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  549. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  550. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  551. //
  552. // ============================================================
  553. //
  554. // minirent — 0.0.1 — A subset of dirent interface for Windows.
  555. //
  556. // https://github.com/tsoding/minirent
  557. //
  558. // ============================================================
  559. //
  560. // ChangeLog (https://semver.org/ is implied)
  561. //
  562. // 0.0.2 Automatically include dirent.h on non-Windows
  563. // platforms
  564. // 0.0.1 First Official Release
  565. #ifndef _WIN32
  566. #include <dirent.h>
  567. #else // _WIN32
  568. #define WIN32_LEAN_AND_MEAN
  569. #include "windows.h"
  570. struct dirent
  571. {
  572. char d_name[MAX_PATH+1];
  573. };
  574. typedef struct DIR DIR;
  575. static DIR *opendir(const char *dirpath);
  576. static struct dirent *readdir(DIR *dirp);
  577. static int closedir(DIR *dirp);
  578. #endif // _WIN32
  579. // minirent.h HEADER END ////////////////////////////////////////
  580. #ifdef _WIN32
  581. char *nob_win32_error_message(DWORD err);
  582. #endif // _WIN32
  583. #endif // NOB_H_
  584. #ifdef NOB_IMPLEMENTATION
  585. // Any messages with the level below nob_minimal_log_level are going to be suppressed.
  586. Nob_Log_Level nob_minimal_log_level = NOB_INFO;
  587. #ifdef _WIN32
  588. // Base on https://stackoverflow.com/a/75644008
  589. // > .NET Core uses 4096 * sizeof(WCHAR) buffer on stack for FormatMessageW call. And...thats it.
  590. // >
  591. // > https://github.com/dotnet/runtime/blob/3b63eb1346f1ddbc921374a5108d025662fb5ffd/src/coreclr/utilcode/posterror.cpp#L264-L265
  592. #ifndef NOB_WIN32_ERR_MSG_SIZE
  593. #define NOB_WIN32_ERR_MSG_SIZE (4 * 1024)
  594. #endif // NOB_WIN32_ERR_MSG_SIZE
  595. char *nob_win32_error_message(DWORD err) {
  596. static char win32ErrMsg[NOB_WIN32_ERR_MSG_SIZE] = {0};
  597. DWORD errMsgSize = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, LANG_USER_DEFAULT, win32ErrMsg,
  598. NOB_WIN32_ERR_MSG_SIZE, NULL);
  599. if (errMsgSize == 0) {
  600. if (GetLastError() != ERROR_MR_MID_NOT_FOUND) {
  601. if (sprintf(win32ErrMsg, "Could not get error message for 0x%lX", err) > 0) {
  602. return (char *)&win32ErrMsg;
  603. } else {
  604. return NULL;
  605. }
  606. } else {
  607. if (sprintf(win32ErrMsg, "Invalid Windows Error code (0x%lX)", err) > 0) {
  608. return (char *)&win32ErrMsg;
  609. } else {
  610. return NULL;
  611. }
  612. }
  613. }
  614. while (errMsgSize > 1 && isspace(win32ErrMsg[errMsgSize - 1])) {
  615. win32ErrMsg[--errMsgSize] = '\0';
  616. }
  617. return win32ErrMsg;
  618. }
  619. #endif // _WIN32
  620. // The implementation idea is stolen from https://github.com/zhiayang/nabs
  621. void nob__go_rebuild_urself(int argc, char **argv, const char *source_path, ...)
  622. {
  623. const char *binary_path = nob_shift(argv, argc);
  624. #ifdef _WIN32
  625. // On Windows executables almost always invoked without extension, so
  626. // it's ./nob, not ./nob.exe. For renaming the extension is a must.
  627. if (!nob_sv_end_with(nob_sv_from_cstr(binary_path), ".exe")) {
  628. binary_path = nob_temp_sprintf("%s.exe", binary_path);
  629. }
  630. #endif
  631. Nob_File_Paths source_paths = {0};
  632. nob_da_append(&source_paths, source_path);
  633. va_list args;
  634. va_start(args, source_path);
  635. for (;;) {
  636. const char *path = va_arg(args, const char*);
  637. if (path == NULL) break;
  638. nob_da_append(&source_paths, path);
  639. }
  640. va_end(args);
  641. int rebuild_is_needed = nob_needs_rebuild(binary_path, source_paths.items, source_paths.count);
  642. if (rebuild_is_needed < 0) exit(1); // error
  643. if (!rebuild_is_needed) { // no rebuild is needed
  644. NOB_FREE(source_paths.items);
  645. return;
  646. }
  647. Nob_Cmd cmd = {0};
  648. const char *old_binary_path = nob_temp_sprintf("%s.old", binary_path);
  649. if (!nob_rename(binary_path, old_binary_path)) exit(1);
  650. nob_cmd_append(&cmd, NOB_REBUILD_URSELF(binary_path, source_path));
  651. if (!nob_cmd_run_sync_and_reset(&cmd)) {
  652. nob_rename(old_binary_path, binary_path);
  653. exit(1);
  654. }
  655. #ifdef NOB_EXPERIMENTAL_DELETE_OLD
  656. // TODO: this is an experimental behavior behind a compilation flag.
  657. // Once it is confirmed that it does not cause much problems on both POSIX and Windows
  658. // we may turn it on by default.
  659. nob_delete_file(old_binary_path);
  660. #endif // NOB_EXPERIMENTAL_DELETE_OLD
  661. nob_cmd_append(&cmd, binary_path);
  662. nob_da_append_many(&cmd, argv, argc);
  663. if (!nob_cmd_run_sync_and_reset(&cmd)) exit(1);
  664. exit(0);
  665. }
  666. static size_t nob_temp_size = 0;
  667. static char nob_temp[NOB_TEMP_CAPACITY] = {0};
  668. bool nob_mkdir_if_not_exists(const char *path)
  669. {
  670. #ifdef _WIN32
  671. int result = mkdir(path);
  672. #else
  673. int result = mkdir(path, 0755);
  674. #endif
  675. if (result < 0) {
  676. if (errno == EEXIST) {
  677. nob_log(NOB_INFO, "directory `%s` already exists", path);
  678. return true;
  679. }
  680. nob_log(NOB_ERROR, "could not create directory `%s`: %s", path, strerror(errno));
  681. return false;
  682. }
  683. nob_log(NOB_INFO, "created directory `%s`", path);
  684. return true;
  685. }
  686. bool nob_copy_file(const char *src_path, const char *dst_path)
  687. {
  688. nob_log(NOB_INFO, "copying %s -> %s", src_path, dst_path);
  689. #ifdef _WIN32
  690. if (!CopyFile(src_path, dst_path, FALSE)) {
  691. nob_log(NOB_ERROR, "Could not copy file: %s", nob_win32_error_message(GetLastError()));
  692. return false;
  693. }
  694. return true;
  695. #else
  696. int src_fd = -1;
  697. int dst_fd = -1;
  698. size_t buf_size = 32*1024;
  699. char *buf = NOB_REALLOC(NULL, buf_size);
  700. NOB_ASSERT(buf != NULL && "Buy more RAM lol!!");
  701. bool result = true;
  702. src_fd = open(src_path, O_RDONLY);
  703. if (src_fd < 0) {
  704. nob_log(NOB_ERROR, "Could not open file %s: %s", src_path, strerror(errno));
  705. nob_return_defer(false);
  706. }
  707. struct stat src_stat;
  708. if (fstat(src_fd, &src_stat) < 0) {
  709. nob_log(NOB_ERROR, "Could not get mode of file %s: %s", src_path, strerror(errno));
  710. nob_return_defer(false);
  711. }
  712. dst_fd = open(dst_path, O_CREAT | O_TRUNC | O_WRONLY, src_stat.st_mode);
  713. if (dst_fd < 0) {
  714. nob_log(NOB_ERROR, "Could not create file %s: %s", dst_path, strerror(errno));
  715. nob_return_defer(false);
  716. }
  717. for (;;) {
  718. ssize_t n = read(src_fd, buf, buf_size);
  719. if (n == 0) break;
  720. if (n < 0) {
  721. nob_log(NOB_ERROR, "Could not read from file %s: %s", src_path, strerror(errno));
  722. nob_return_defer(false);
  723. }
  724. char *buf2 = buf;
  725. while (n > 0) {
  726. ssize_t m = write(dst_fd, buf2, n);
  727. if (m < 0) {
  728. nob_log(NOB_ERROR, "Could not write to file %s: %s", dst_path, strerror(errno));
  729. nob_return_defer(false);
  730. }
  731. n -= m;
  732. buf2 += m;
  733. }
  734. }
  735. defer:
  736. NOB_FREE(buf);
  737. close(src_fd);
  738. close(dst_fd);
  739. return result;
  740. #endif
  741. }
  742. void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render)
  743. {
  744. for (size_t i = 0; i < cmd.count; ++i) {
  745. const char *arg = cmd.items[i];
  746. if (arg == NULL) break;
  747. if (i > 0) nob_sb_append_cstr(render, " ");
  748. if (!strchr(arg, ' ')) {
  749. nob_sb_append_cstr(render, arg);
  750. } else {
  751. nob_da_append(render, '\'');
  752. nob_sb_append_cstr(render, arg);
  753. nob_da_append(render, '\'');
  754. }
  755. }
  756. }
  757. #ifdef _WIN32
  758. // https://learn.microsoft.com/en-gb/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
  759. static void nob__win32_cmd_quote(Nob_Cmd cmd, Nob_String_Builder *quoted)
  760. {
  761. for (size_t i = 0; i < cmd.count; ++i) {
  762. const char *arg = cmd.items[i];
  763. if (arg == NULL) break;
  764. size_t len = strlen(arg);
  765. if (i > 0) nob_da_append(quoted, ' ');
  766. if (len != 0 && NULL == strpbrk(arg, " \t\n\v\"")) {
  767. // no need to quote
  768. nob_da_append_many(quoted, arg, len);
  769. } else {
  770. // we need to escape:
  771. // 1. double quotes in the original arg
  772. // 2. consequent backslashes before a double quote
  773. size_t backslashes = 0;
  774. nob_da_append(quoted, '\"');
  775. for (size_t j = 0; j < len; ++j) {
  776. char x = arg[j];
  777. if (x == '\\') {
  778. backslashes += 1;
  779. } else {
  780. if (x == '\"') {
  781. // escape backslashes (if any) and the double quote
  782. for (size_t k = 0; k < 1+backslashes; ++k) {
  783. nob_da_append(quoted, '\\');
  784. }
  785. }
  786. backslashes = 0;
  787. }
  788. nob_da_append(quoted, x);
  789. }
  790. // escape backslashes (if any)
  791. for (size_t k = 0; k < backslashes; ++k) {
  792. nob_da_append(quoted, '\\');
  793. }
  794. nob_da_append(quoted, '\"');
  795. }
  796. }
  797. }
  798. #endif
  799. Nob_Proc nob_cmd_run_async_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect)
  800. {
  801. if (cmd.count < 1) {
  802. nob_log(NOB_ERROR, "Could not run empty command");
  803. return NOB_INVALID_PROC;
  804. }
  805. Nob_String_Builder sb = {0};
  806. nob_cmd_render(cmd, &sb);
  807. nob_sb_append_null(&sb);
  808. nob_log(NOB_INFO, "CMD: %s", sb.items);
  809. nob_sb_free(sb);
  810. memset(&sb, 0, sizeof(sb));
  811. #ifdef _WIN32
  812. // https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
  813. STARTUPINFO siStartInfo;
  814. ZeroMemory(&siStartInfo, sizeof(siStartInfo));
  815. siStartInfo.cb = sizeof(STARTUPINFO);
  816. // NOTE: theoretically setting NULL to std handles should not be a problem
  817. // https://docs.microsoft.com/en-us/windows/console/getstdhandle?redirectedfrom=MSDN#attachdetach-behavior
  818. // TODO: check for errors in GetStdHandle
  819. siStartInfo.hStdError = redirect.fderr ? *redirect.fderr : GetStdHandle(STD_ERROR_HANDLE);
  820. siStartInfo.hStdOutput = redirect.fdout ? *redirect.fdout : GetStdHandle(STD_OUTPUT_HANDLE);
  821. siStartInfo.hStdInput = redirect.fdin ? *redirect.fdin : GetStdHandle(STD_INPUT_HANDLE);
  822. siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
  823. PROCESS_INFORMATION piProcInfo;
  824. ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
  825. nob__win32_cmd_quote(cmd, &sb);
  826. nob_sb_append_null(&sb);
  827. BOOL bSuccess = CreateProcessA(NULL, sb.items, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);
  828. nob_sb_free(sb);
  829. if (!bSuccess) {
  830. nob_log(NOB_ERROR, "Could not create child process for %s: %s", cmd.items[0], nob_win32_error_message(GetLastError()));
  831. return NOB_INVALID_PROC;
  832. }
  833. CloseHandle(piProcInfo.hThread);
  834. return piProcInfo.hProcess;
  835. #else
  836. pid_t cpid = fork();
  837. if (cpid < 0) {
  838. nob_log(NOB_ERROR, "Could not fork child process: %s", strerror(errno));
  839. return NOB_INVALID_PROC;
  840. }
  841. if (cpid == 0) {
  842. if (redirect.fdin) {
  843. if (dup2(*redirect.fdin, STDIN_FILENO) < 0) {
  844. nob_log(NOB_ERROR, "Could not setup stdin for child process: %s", strerror(errno));
  845. exit(1);
  846. }
  847. }
  848. if (redirect.fdout) {
  849. if (dup2(*redirect.fdout, STDOUT_FILENO) < 0) {
  850. nob_log(NOB_ERROR, "Could not setup stdout for child process: %s", strerror(errno));
  851. exit(1);
  852. }
  853. }
  854. if (redirect.fderr) {
  855. if (dup2(*redirect.fderr, STDERR_FILENO) < 0) {
  856. nob_log(NOB_ERROR, "Could not setup stderr for child process: %s", strerror(errno));
  857. exit(1);
  858. }
  859. }
  860. // NOTE: This leaks a bit of memory in the child process.
  861. // But do we actually care? It's a one off leak anyway...
  862. Nob_Cmd cmd_null = {0};
  863. nob_da_append_many(&cmd_null, cmd.items, cmd.count);
  864. nob_cmd_append(&cmd_null, NULL);
  865. if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) {
  866. nob_log(NOB_ERROR, "Could not exec child process for %s: %s", cmd.items[0], strerror(errno));
  867. exit(1);
  868. }
  869. NOB_UNREACHABLE("nob_cmd_run_async_redirect");
  870. }
  871. return cpid;
  872. #endif
  873. }
  874. Nob_Proc nob_cmd_run_async_and_reset(Nob_Cmd *cmd)
  875. {
  876. Nob_Proc proc = nob_cmd_run_async(*cmd);
  877. cmd->count = 0;
  878. return proc;
  879. }
  880. Nob_Proc nob_cmd_run_async_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect)
  881. {
  882. Nob_Proc proc = nob_cmd_run_async_redirect(*cmd, redirect);
  883. cmd->count = 0;
  884. if (redirect.fdin) {
  885. nob_fd_close(*redirect.fdin);
  886. *redirect.fdin = NOB_INVALID_FD;
  887. }
  888. if (redirect.fdout) {
  889. nob_fd_close(*redirect.fdout);
  890. *redirect.fdout = NOB_INVALID_FD;
  891. }
  892. if (redirect.fderr) {
  893. nob_fd_close(*redirect.fderr);
  894. *redirect.fderr = NOB_INVALID_FD;
  895. }
  896. return proc;
  897. }
  898. Nob_Fd nob_fd_open_for_read(const char *path)
  899. {
  900. #ifndef _WIN32
  901. Nob_Fd result = open(path, O_RDONLY);
  902. if (result < 0) {
  903. nob_log(NOB_ERROR, "Could not open file %s: %s", path, strerror(errno));
  904. return NOB_INVALID_FD;
  905. }
  906. return result;
  907. #else
  908. // https://docs.microsoft.com/en-us/windows/win32/fileio/opening-a-file-for-reading-or-writing
  909. SECURITY_ATTRIBUTES saAttr = {0};
  910. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  911. saAttr.bInheritHandle = TRUE;
  912. Nob_Fd result = CreateFile(
  913. path,
  914. GENERIC_READ,
  915. 0,
  916. &saAttr,
  917. OPEN_EXISTING,
  918. FILE_ATTRIBUTE_READONLY,
  919. NULL);
  920. if (result == INVALID_HANDLE_VALUE) {
  921. nob_log(NOB_ERROR, "Could not open file %s: %s", path, nob_win32_error_message(GetLastError()));
  922. return NOB_INVALID_FD;
  923. }
  924. return result;
  925. #endif // _WIN32
  926. }
  927. Nob_Fd nob_fd_open_for_write(const char *path)
  928. {
  929. #ifndef _WIN32
  930. Nob_Fd result = open(path,
  931. O_WRONLY | O_CREAT | O_TRUNC,
  932. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  933. if (result < 0) {
  934. nob_log(NOB_ERROR, "could not open file %s: %s", path, strerror(errno));
  935. return NOB_INVALID_FD;
  936. }
  937. return result;
  938. #else
  939. SECURITY_ATTRIBUTES saAttr = {0};
  940. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  941. saAttr.bInheritHandle = TRUE;
  942. Nob_Fd result = CreateFile(
  943. path, // name of the write
  944. GENERIC_WRITE, // open for writing
  945. 0, // do not share
  946. &saAttr, // default security
  947. CREATE_ALWAYS, // create always
  948. FILE_ATTRIBUTE_NORMAL, // normal file
  949. NULL // no attr. template
  950. );
  951. if (result == INVALID_HANDLE_VALUE) {
  952. nob_log(NOB_ERROR, "Could not open file %s: %s", path, nob_win32_error_message(GetLastError()));
  953. return NOB_INVALID_FD;
  954. }
  955. return result;
  956. #endif // _WIN32
  957. }
  958. void nob_fd_close(Nob_Fd fd)
  959. {
  960. #ifdef _WIN32
  961. CloseHandle(fd);
  962. #else
  963. close(fd);
  964. #endif // _WIN32
  965. }
  966. bool nob_procs_wait(Nob_Procs procs)
  967. {
  968. bool success = true;
  969. for (size_t i = 0; i < procs.count; ++i) {
  970. success = nob_proc_wait(procs.items[i]) && success;
  971. }
  972. return success;
  973. }
  974. bool nob_procs_wait_and_reset(Nob_Procs *procs)
  975. {
  976. bool success = nob_procs_wait(*procs);
  977. procs->count = 0;
  978. return success;
  979. }
  980. bool nob_proc_wait(Nob_Proc proc)
  981. {
  982. if (proc == NOB_INVALID_PROC) return false;
  983. #ifdef _WIN32
  984. DWORD result = WaitForSingleObject(
  985. proc, // HANDLE hHandle,
  986. INFINITE // DWORD dwMilliseconds
  987. );
  988. if (result == WAIT_FAILED) {
  989. nob_log(NOB_ERROR, "could not wait on child process: %s", nob_win32_error_message(GetLastError()));
  990. return false;
  991. }
  992. DWORD exit_status;
  993. if (!GetExitCodeProcess(proc, &exit_status)) {
  994. nob_log(NOB_ERROR, "could not get process exit code: %s", nob_win32_error_message(GetLastError()));
  995. return false;
  996. }
  997. if (exit_status != 0) {
  998. nob_log(NOB_ERROR, "command exited with exit code %lu", exit_status);
  999. return false;
  1000. }
  1001. CloseHandle(proc);
  1002. return true;
  1003. #else
  1004. for (;;) {
  1005. int wstatus = 0;
  1006. if (waitpid(proc, &wstatus, 0) < 0) {
  1007. nob_log(NOB_ERROR, "could not wait on command (pid %d): %s", proc, strerror(errno));
  1008. return false;
  1009. }
  1010. if (WIFEXITED(wstatus)) {
  1011. int exit_status = WEXITSTATUS(wstatus);
  1012. if (exit_status != 0) {
  1013. nob_log(NOB_ERROR, "command exited with exit code %d", exit_status);
  1014. return false;
  1015. }
  1016. break;
  1017. }
  1018. if (WIFSIGNALED(wstatus)) {
  1019. nob_log(NOB_ERROR, "command process was terminated by signal %d", WTERMSIG(wstatus));
  1020. return false;
  1021. }
  1022. }
  1023. return true;
  1024. #endif
  1025. }
  1026. bool nob_procs_append_with_flush(Nob_Procs *procs, Nob_Proc proc, size_t max_procs_count)
  1027. {
  1028. nob_da_append(procs, proc);
  1029. if (procs->count >= max_procs_count) {
  1030. if (!nob_procs_wait_and_reset(procs)) return false;
  1031. }
  1032. return true;
  1033. }
  1034. bool nob_cmd_run_sync_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect)
  1035. {
  1036. Nob_Proc p = nob_cmd_run_async_redirect(cmd, redirect);
  1037. if (p == NOB_INVALID_PROC) return false;
  1038. return nob_proc_wait(p);
  1039. }
  1040. bool nob_cmd_run_sync(Nob_Cmd cmd)
  1041. {
  1042. Nob_Proc p = nob_cmd_run_async(cmd);
  1043. if (p == NOB_INVALID_PROC) return false;
  1044. return nob_proc_wait(p);
  1045. }
  1046. bool nob_cmd_run_sync_and_reset(Nob_Cmd *cmd)
  1047. {
  1048. bool p = nob_cmd_run_sync(*cmd);
  1049. cmd->count = 0;
  1050. return p;
  1051. }
  1052. bool nob_cmd_run_sync_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect)
  1053. {
  1054. bool p = nob_cmd_run_sync_redirect(*cmd, redirect);
  1055. cmd->count = 0;
  1056. if (redirect.fdin) {
  1057. nob_fd_close(*redirect.fdin);
  1058. *redirect.fdin = NOB_INVALID_FD;
  1059. }
  1060. if (redirect.fdout) {
  1061. nob_fd_close(*redirect.fdout);
  1062. *redirect.fdout = NOB_INVALID_FD;
  1063. }
  1064. if (redirect.fderr) {
  1065. nob_fd_close(*redirect.fderr);
  1066. *redirect.fderr = NOB_INVALID_FD;
  1067. }
  1068. return p;
  1069. }
  1070. void nob_log(Nob_Log_Level level, const char *fmt, ...)
  1071. {
  1072. if (level < nob_minimal_log_level) return;
  1073. switch (level) {
  1074. case NOB_INFO:
  1075. fprintf(stderr, "[INFO] ");
  1076. break;
  1077. case NOB_WARNING:
  1078. fprintf(stderr, "[WARNING] ");
  1079. break;
  1080. case NOB_ERROR:
  1081. fprintf(stderr, "[ERROR] ");
  1082. break;
  1083. case NOB_NO_LOGS: return;
  1084. default:
  1085. NOB_UNREACHABLE("nob_log");
  1086. }
  1087. va_list args;
  1088. va_start(args, fmt);
  1089. vfprintf(stderr, fmt, args);
  1090. va_end(args);
  1091. fprintf(stderr, "\n");
  1092. }
  1093. bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children)
  1094. {
  1095. bool result = true;
  1096. DIR *dir = NULL;
  1097. dir = opendir(parent);
  1098. if (dir == NULL) {
  1099. #ifdef _WIN32
  1100. nob_log(NOB_ERROR, "Could not open directory %s: %s", parent, nob_win32_error_message(GetLastError()));
  1101. #else
  1102. nob_log(NOB_ERROR, "Could not open directory %s: %s", parent, strerror(errno));
  1103. #endif // _WIN32
  1104. nob_return_defer(false);
  1105. }
  1106. errno = 0;
  1107. struct dirent *ent = readdir(dir);
  1108. while (ent != NULL) {
  1109. nob_da_append(children, nob_temp_strdup(ent->d_name));
  1110. ent = readdir(dir);
  1111. }
  1112. if (errno != 0) {
  1113. #ifdef _WIN32
  1114. nob_log(NOB_ERROR, "Could not read directory %s: %s", parent, nob_win32_error_message(GetLastError()));
  1115. #else
  1116. nob_log(NOB_ERROR, "Could not read directory %s: %s", parent, strerror(errno));
  1117. #endif // _WIN32
  1118. nob_return_defer(false);
  1119. }
  1120. defer:
  1121. if (dir) closedir(dir);
  1122. return result;
  1123. }
  1124. bool nob_write_entire_file(const char *path, const void *data, size_t size)
  1125. {
  1126. bool result = true;
  1127. FILE *f = fopen(path, "wb");
  1128. if (f == NULL) {
  1129. nob_log(NOB_ERROR, "Could not open file %s for writing: %s\n", path, strerror(errno));
  1130. nob_return_defer(false);
  1131. }
  1132. // len
  1133. // v
  1134. // aaaaaaaaaa
  1135. // ^
  1136. // data
  1137. const char *buf = data;
  1138. while (size > 0) {
  1139. size_t n = fwrite(buf, 1, size, f);
  1140. if (ferror(f)) {
  1141. nob_log(NOB_ERROR, "Could not write into file %s: %s\n", path, strerror(errno));
  1142. nob_return_defer(false);
  1143. }
  1144. size -= n;
  1145. buf += n;
  1146. }
  1147. defer:
  1148. if (f) fclose(f);
  1149. return result;
  1150. }
  1151. Nob_File_Type nob_get_file_type(const char *path)
  1152. {
  1153. #ifdef _WIN32
  1154. DWORD attr = GetFileAttributesA(path);
  1155. if (attr == INVALID_FILE_ATTRIBUTES) {
  1156. nob_log(NOB_ERROR, "Could not get file attributes of %s: %s", path, nob_win32_error_message(GetLastError()));
  1157. return -1;
  1158. }
  1159. if (attr & FILE_ATTRIBUTE_DIRECTORY) return NOB_FILE_DIRECTORY;
  1160. // TODO: detect symlinks on Windows (whatever that means on Windows anyway)
  1161. return NOB_FILE_REGULAR;
  1162. #else // _WIN32
  1163. struct stat statbuf;
  1164. if (stat(path, &statbuf) < 0) {
  1165. nob_log(NOB_ERROR, "Could not get stat of %s: %s", path, strerror(errno));
  1166. return -1;
  1167. }
  1168. if (S_ISREG(statbuf.st_mode)) return NOB_FILE_REGULAR;
  1169. if (S_ISDIR(statbuf.st_mode)) return NOB_FILE_DIRECTORY;
  1170. if (S_ISLNK(statbuf.st_mode)) return NOB_FILE_SYMLINK;
  1171. return NOB_FILE_OTHER;
  1172. #endif // _WIN32
  1173. }
  1174. bool nob_delete_file(const char *path)
  1175. {
  1176. nob_log(NOB_INFO, "deleting %s", path);
  1177. #ifdef _WIN32
  1178. if (!DeleteFileA(path)) {
  1179. nob_log(NOB_ERROR, "Could not delete file %s: %s", path, nob_win32_error_message(GetLastError()));
  1180. return false;
  1181. }
  1182. return true;
  1183. #else
  1184. if (remove(path) < 0) {
  1185. nob_log(NOB_ERROR, "Could not delete file %s: %s", path, strerror(errno));
  1186. return false;
  1187. }
  1188. return true;
  1189. #endif // _WIN32
  1190. }
  1191. bool nob_copy_directory_recursively(const char *src_path, const char *dst_path)
  1192. {
  1193. bool result = true;
  1194. Nob_File_Paths children = {0};
  1195. Nob_String_Builder src_sb = {0};
  1196. Nob_String_Builder dst_sb = {0};
  1197. size_t temp_checkpoint = nob_temp_save();
  1198. Nob_File_Type type = nob_get_file_type(src_path);
  1199. if (type < 0) return false;
  1200. switch (type) {
  1201. case NOB_FILE_DIRECTORY: {
  1202. if (!nob_mkdir_if_not_exists(dst_path)) nob_return_defer(false);
  1203. if (!nob_read_entire_dir(src_path, &children)) nob_return_defer(false);
  1204. for (size_t i = 0; i < children.count; ++i) {
  1205. if (strcmp(children.items[i], ".") == 0) continue;
  1206. if (strcmp(children.items[i], "..") == 0) continue;
  1207. src_sb.count = 0;
  1208. nob_sb_append_cstr(&src_sb, src_path);
  1209. nob_sb_append_cstr(&src_sb, "/");
  1210. nob_sb_append_cstr(&src_sb, children.items[i]);
  1211. nob_sb_append_null(&src_sb);
  1212. dst_sb.count = 0;
  1213. nob_sb_append_cstr(&dst_sb, dst_path);
  1214. nob_sb_append_cstr(&dst_sb, "/");
  1215. nob_sb_append_cstr(&dst_sb, children.items[i]);
  1216. nob_sb_append_null(&dst_sb);
  1217. if (!nob_copy_directory_recursively(src_sb.items, dst_sb.items)) {
  1218. nob_return_defer(false);
  1219. }
  1220. }
  1221. } break;
  1222. case NOB_FILE_REGULAR: {
  1223. if (!nob_copy_file(src_path, dst_path)) {
  1224. nob_return_defer(false);
  1225. }
  1226. } break;
  1227. case NOB_FILE_SYMLINK: {
  1228. nob_log(NOB_WARNING, "TODO: Copying symlinks is not supported yet");
  1229. } break;
  1230. case NOB_FILE_OTHER: {
  1231. nob_log(NOB_ERROR, "Unsupported type of file %s", src_path);
  1232. nob_return_defer(false);
  1233. } break;
  1234. default: NOB_UNREACHABLE("nob_copy_directory_recursively");
  1235. }
  1236. defer:
  1237. nob_temp_rewind(temp_checkpoint);
  1238. nob_da_free(src_sb);
  1239. nob_da_free(dst_sb);
  1240. nob_da_free(children);
  1241. return result;
  1242. }
  1243. char *nob_temp_strdup(const char *cstr)
  1244. {
  1245. size_t n = strlen(cstr);
  1246. char *result = nob_temp_alloc(n + 1);
  1247. NOB_ASSERT(result != NULL && "Increase NOB_TEMP_CAPACITY");
  1248. memcpy(result, cstr, n);
  1249. result[n] = '\0';
  1250. return result;
  1251. }
  1252. void *nob_temp_alloc(size_t size)
  1253. {
  1254. if (nob_temp_size + size > NOB_TEMP_CAPACITY) return NULL;
  1255. void *result = &nob_temp[nob_temp_size];
  1256. nob_temp_size += size;
  1257. return result;
  1258. }
  1259. char *nob_temp_sprintf(const char *format, ...)
  1260. {
  1261. va_list args;
  1262. va_start(args, format);
  1263. int n = vsnprintf(NULL, 0, format, args);
  1264. va_end(args);
  1265. NOB_ASSERT(n >= 0);
  1266. char *result = nob_temp_alloc(n + 1);
  1267. NOB_ASSERT(result != NULL && "Extend the size of the temporary allocator");
  1268. // TODO: use proper arenas for the temporary allocator;
  1269. va_start(args, format);
  1270. vsnprintf(result, n + 1, format, args);
  1271. va_end(args);
  1272. return result;
  1273. }
  1274. void nob_temp_reset(void)
  1275. {
  1276. nob_temp_size = 0;
  1277. }
  1278. size_t nob_temp_save(void)
  1279. {
  1280. return nob_temp_size;
  1281. }
  1282. void nob_temp_rewind(size_t checkpoint)
  1283. {
  1284. nob_temp_size = checkpoint;
  1285. }
  1286. const char *nob_temp_sv_to_cstr(Nob_String_View sv)
  1287. {
  1288. char *result = nob_temp_alloc(sv.count + 1);
  1289. NOB_ASSERT(result != NULL && "Extend the size of the temporary allocator");
  1290. memcpy(result, sv.data, sv.count);
  1291. result[sv.count] = '\0';
  1292. return result;
  1293. }
  1294. int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count)
  1295. {
  1296. #ifdef _WIN32
  1297. BOOL bSuccess;
  1298. HANDLE output_path_fd = CreateFile(output_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  1299. if (output_path_fd == INVALID_HANDLE_VALUE) {
  1300. // NOTE: if output does not exist it 100% must be rebuilt
  1301. if (GetLastError() == ERROR_FILE_NOT_FOUND) return 1;
  1302. nob_log(NOB_ERROR, "Could not open file %s: %s", output_path, nob_win32_error_message(GetLastError()));
  1303. return -1;
  1304. }
  1305. FILETIME output_path_time;
  1306. bSuccess = GetFileTime(output_path_fd, NULL, NULL, &output_path_time);
  1307. CloseHandle(output_path_fd);
  1308. if (!bSuccess) {
  1309. nob_log(NOB_ERROR, "Could not get time of %s: %s", output_path, nob_win32_error_message(GetLastError()));
  1310. return -1;
  1311. }
  1312. for (size_t i = 0; i < input_paths_count; ++i) {
  1313. const char *input_path = input_paths[i];
  1314. HANDLE input_path_fd = CreateFile(input_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  1315. if (input_path_fd == INVALID_HANDLE_VALUE) {
  1316. // NOTE: non-existing input is an error cause it is needed for building in the first place
  1317. nob_log(NOB_ERROR, "Could not open file %s: %s", input_path, nob_win32_error_message(GetLastError()));
  1318. return -1;
  1319. }
  1320. FILETIME input_path_time;
  1321. bSuccess = GetFileTime(input_path_fd, NULL, NULL, &input_path_time);
  1322. CloseHandle(input_path_fd);
  1323. if (!bSuccess) {
  1324. nob_log(NOB_ERROR, "Could not get time of %s: %s", input_path, nob_win32_error_message(GetLastError()));
  1325. return -1;
  1326. }
  1327. // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild
  1328. if (CompareFileTime(&input_path_time, &output_path_time) == 1) return 1;
  1329. }
  1330. return 0;
  1331. #else
  1332. struct stat statbuf = {0};
  1333. if (stat(output_path, &statbuf) < 0) {
  1334. // NOTE: if output does not exist it 100% must be rebuilt
  1335. if (errno == ENOENT) return 1;
  1336. nob_log(NOB_ERROR, "could not stat %s: %s", output_path, strerror(errno));
  1337. return -1;
  1338. }
  1339. int output_path_time = statbuf.st_mtime;
  1340. for (size_t i = 0; i < input_paths_count; ++i) {
  1341. const char *input_path = input_paths[i];
  1342. if (stat(input_path, &statbuf) < 0) {
  1343. // NOTE: non-existing input is an error cause it is needed for building in the first place
  1344. nob_log(NOB_ERROR, "could not stat %s: %s", input_path, strerror(errno));
  1345. return -1;
  1346. }
  1347. int input_path_time = statbuf.st_mtime;
  1348. // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild
  1349. if (input_path_time > output_path_time) return 1;
  1350. }
  1351. return 0;
  1352. #endif
  1353. }
  1354. int nob_needs_rebuild1(const char *output_path, const char *input_path)
  1355. {
  1356. return nob_needs_rebuild(output_path, &input_path, 1);
  1357. }
  1358. const char *nob_path_name(const char *path)
  1359. {
  1360. #ifdef _WIN32
  1361. const char *p1 = strrchr(path, '/');
  1362. const char *p2 = strrchr(path, '\\');
  1363. const char *p = (p1 > p2)? p1 : p2; // NULL is ignored if the other search is successful
  1364. return p ? p + 1 : path;
  1365. #else
  1366. const char *p = strrchr(path, '/');
  1367. return p ? p + 1 : path;
  1368. #endif // _WIN32
  1369. }
  1370. bool nob_rename(const char *old_path, const char *new_path)
  1371. {
  1372. nob_log(NOB_INFO, "renaming %s -> %s", old_path, new_path);
  1373. #ifdef _WIN32
  1374. if (!MoveFileEx(old_path, new_path, MOVEFILE_REPLACE_EXISTING)) {
  1375. nob_log(NOB_ERROR, "could not rename %s to %s: %s", old_path, new_path, nob_win32_error_message(GetLastError()));
  1376. return false;
  1377. }
  1378. #else
  1379. if (rename(old_path, new_path) < 0) {
  1380. nob_log(NOB_ERROR, "could not rename %s to %s: %s", old_path, new_path, strerror(errno));
  1381. return false;
  1382. }
  1383. #endif // _WIN32
  1384. return true;
  1385. }
  1386. bool nob_read_entire_file(const char *path, Nob_String_Builder *sb)
  1387. {
  1388. bool result = true;
  1389. FILE *f = fopen(path, "rb");
  1390. if (f == NULL) nob_return_defer(false);
  1391. if (fseek(f, 0, SEEK_END) < 0) nob_return_defer(false);
  1392. #ifndef _WIN32
  1393. long m = ftell(f);
  1394. #else
  1395. long long m = _ftelli64(f);
  1396. #endif
  1397. if (m < 0) nob_return_defer(false);
  1398. if (fseek(f, 0, SEEK_SET) < 0) nob_return_defer(false);
  1399. size_t new_count = sb->count + m;
  1400. if (new_count > sb->capacity) {
  1401. sb->items = NOB_REALLOC(sb->items, new_count);
  1402. NOB_ASSERT(sb->items != NULL && "Buy more RAM lool!!");
  1403. sb->capacity = new_count;
  1404. }
  1405. fread(sb->items + sb->count, m, 1, f);
  1406. if (ferror(f)) {
  1407. // TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case.
  1408. nob_return_defer(false);
  1409. }
  1410. sb->count = new_count;
  1411. defer:
  1412. if (!result) nob_log(NOB_ERROR, "Could not read file %s: %s", path, strerror(errno));
  1413. if (f) fclose(f);
  1414. return result;
  1415. }
  1416. int nob_sb_appendf(Nob_String_Builder *sb, const char *fmt, ...)
  1417. {
  1418. va_list args;
  1419. va_start(args, fmt);
  1420. int n = vsnprintf(NULL, 0, fmt, args);
  1421. va_end(args);
  1422. // NOTE: the new_capacity needs to be +1 because of the null terminator.
  1423. // However, further below we increase sb->count by n, not n + 1.
  1424. // This is because we don't want the sb to include the null terminator. The user can always sb_append_null() if they want it
  1425. nob_da_reserve(sb, sb->count + n + 1);
  1426. char *dest = sb->items + sb->count;
  1427. va_start(args, fmt);
  1428. vsnprintf(dest, n+1, fmt, args);
  1429. va_end(args);
  1430. sb->count += n;
  1431. return n;
  1432. }
  1433. Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim)
  1434. {
  1435. size_t i = 0;
  1436. while (i < sv->count && sv->data[i] != delim) {
  1437. i += 1;
  1438. }
  1439. Nob_String_View result = nob_sv_from_parts(sv->data, i);
  1440. if (i < sv->count) {
  1441. sv->count -= i + 1;
  1442. sv->data += i + 1;
  1443. } else {
  1444. sv->count -= i;
  1445. sv->data += i;
  1446. }
  1447. return result;
  1448. }
  1449. Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n)
  1450. {
  1451. if (n > sv->count) {
  1452. n = sv->count;
  1453. }
  1454. Nob_String_View result = nob_sv_from_parts(sv->data, n);
  1455. sv->data += n;
  1456. sv->count -= n;
  1457. return result;
  1458. }
  1459. Nob_String_View nob_sv_from_parts(const char *data, size_t count)
  1460. {
  1461. Nob_String_View sv;
  1462. sv.count = count;
  1463. sv.data = data;
  1464. return sv;
  1465. }
  1466. Nob_String_View nob_sv_trim_left(Nob_String_View sv)
  1467. {
  1468. size_t i = 0;
  1469. while (i < sv.count && isspace(sv.data[i])) {
  1470. i += 1;
  1471. }
  1472. return nob_sv_from_parts(sv.data + i, sv.count - i);
  1473. }
  1474. Nob_String_View nob_sv_trim_right(Nob_String_View sv)
  1475. {
  1476. size_t i = 0;
  1477. while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) {
  1478. i += 1;
  1479. }
  1480. return nob_sv_from_parts(sv.data, sv.count - i);
  1481. }
  1482. Nob_String_View nob_sv_trim(Nob_String_View sv)
  1483. {
  1484. return nob_sv_trim_right(nob_sv_trim_left(sv));
  1485. }
  1486. Nob_String_View nob_sv_from_cstr(const char *cstr)
  1487. {
  1488. return nob_sv_from_parts(cstr, strlen(cstr));
  1489. }
  1490. bool nob_sv_eq(Nob_String_View a, Nob_String_View b)
  1491. {
  1492. if (a.count != b.count) {
  1493. return false;
  1494. } else {
  1495. return memcmp(a.data, b.data, a.count) == 0;
  1496. }
  1497. }
  1498. bool nob_sv_end_with(Nob_String_View sv, const char *cstr)
  1499. {
  1500. size_t cstr_count = strlen(cstr);
  1501. if (sv.count >= cstr_count) {
  1502. size_t ending_start = sv.count - cstr_count;
  1503. Nob_String_View sv_ending = nob_sv_from_parts(sv.data + ending_start, cstr_count);
  1504. return nob_sv_eq(sv_ending, nob_sv_from_cstr(cstr));
  1505. }
  1506. return false;
  1507. }
  1508. bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix)
  1509. {
  1510. if (expected_prefix.count <= sv.count) {
  1511. Nob_String_View actual_prefix = nob_sv_from_parts(sv.data, expected_prefix.count);
  1512. return nob_sv_eq(expected_prefix, actual_prefix);
  1513. }
  1514. return false;
  1515. }
  1516. // RETURNS:
  1517. // 0 - file does not exists
  1518. // 1 - file exists
  1519. // -1 - error while checking if file exists. The error is logged
  1520. int nob_file_exists(const char *file_path)
  1521. {
  1522. #if _WIN32
  1523. // TODO: distinguish between "does not exists" and other errors
  1524. DWORD dwAttrib = GetFileAttributesA(file_path);
  1525. return dwAttrib != INVALID_FILE_ATTRIBUTES;
  1526. #else
  1527. struct stat statbuf;
  1528. if (stat(file_path, &statbuf) < 0) {
  1529. if (errno == ENOENT) return 0;
  1530. nob_log(NOB_ERROR, "Could not check if file %s exists: %s", file_path, strerror(errno));
  1531. return -1;
  1532. }
  1533. return 1;
  1534. #endif
  1535. }
  1536. const char *nob_get_current_dir_temp(void)
  1537. {
  1538. #ifdef _WIN32
  1539. DWORD nBufferLength = GetCurrentDirectory(0, NULL);
  1540. if (nBufferLength == 0) {
  1541. nob_log(NOB_ERROR, "could not get current directory: %s", nob_win32_error_message(GetLastError()));
  1542. return NULL;
  1543. }
  1544. char *buffer = (char*) nob_temp_alloc(nBufferLength);
  1545. if (GetCurrentDirectory(nBufferLength, buffer) == 0) {
  1546. nob_log(NOB_ERROR, "could not get current directory: %s", nob_win32_error_message(GetLastError()));
  1547. return NULL;
  1548. }
  1549. return buffer;
  1550. #else
  1551. char *buffer = (char*) nob_temp_alloc(PATH_MAX);
  1552. if (getcwd(buffer, PATH_MAX) == NULL) {
  1553. nob_log(NOB_ERROR, "could not get current directory: %s", strerror(errno));
  1554. return NULL;
  1555. }
  1556. return buffer;
  1557. #endif // _WIN32
  1558. }
  1559. bool nob_set_current_dir(const char *path)
  1560. {
  1561. #ifdef _WIN32
  1562. if (!SetCurrentDirectory(path)) {
  1563. nob_log(NOB_ERROR, "could not set current directory to %s: %s", path, nob_win32_error_message(GetLastError()));
  1564. return false;
  1565. }
  1566. return true;
  1567. #else
  1568. if (chdir(path) < 0) {
  1569. nob_log(NOB_ERROR, "could not set current directory to %s: %s", path, strerror(errno));
  1570. return false;
  1571. }
  1572. return true;
  1573. #endif // _WIN32
  1574. }
  1575. // minirent.h SOURCE BEGIN ////////////////////////////////////////
  1576. #ifdef _WIN32
  1577. struct DIR
  1578. {
  1579. HANDLE hFind;
  1580. WIN32_FIND_DATA data;
  1581. struct dirent *dirent;
  1582. };
  1583. DIR *opendir(const char *dirpath)
  1584. {
  1585. NOB_ASSERT(dirpath);
  1586. char buffer[MAX_PATH];
  1587. snprintf(buffer, MAX_PATH, "%s\\*", dirpath);
  1588. DIR *dir = (DIR*)NOB_REALLOC(NULL, sizeof(DIR));
  1589. memset(dir, 0, sizeof(DIR));
  1590. dir->hFind = FindFirstFile(buffer, &dir->data);
  1591. if (dir->hFind == INVALID_HANDLE_VALUE) {
  1592. // TODO: opendir should set errno accordingly on FindFirstFile fail
  1593. // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
  1594. errno = ENOSYS;
  1595. goto fail;
  1596. }
  1597. return dir;
  1598. fail:
  1599. if (dir) {
  1600. NOB_FREE(dir);
  1601. }
  1602. return NULL;
  1603. }
  1604. struct dirent *readdir(DIR *dirp)
  1605. {
  1606. NOB_ASSERT(dirp);
  1607. if (dirp->dirent == NULL) {
  1608. dirp->dirent = (struct dirent*)NOB_REALLOC(NULL, sizeof(struct dirent));
  1609. memset(dirp->dirent, 0, sizeof(struct dirent));
  1610. } else {
  1611. if(!FindNextFile(dirp->hFind, &dirp->data)) {
  1612. if (GetLastError() != ERROR_NO_MORE_FILES) {
  1613. // TODO: readdir should set errno accordingly on FindNextFile fail
  1614. // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
  1615. errno = ENOSYS;
  1616. }
  1617. return NULL;
  1618. }
  1619. }
  1620. memset(dirp->dirent->d_name, 0, sizeof(dirp->dirent->d_name));
  1621. strncpy(
  1622. dirp->dirent->d_name,
  1623. dirp->data.cFileName,
  1624. sizeof(dirp->dirent->d_name) - 1);
  1625. return dirp->dirent;
  1626. }
  1627. int closedir(DIR *dirp)
  1628. {
  1629. NOB_ASSERT(dirp);
  1630. if(!FindClose(dirp->hFind)) {
  1631. // TODO: closedir should set errno accordingly on FindClose fail
  1632. // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
  1633. errno = ENOSYS;
  1634. return -1;
  1635. }
  1636. if (dirp->dirent) {
  1637. NOB_FREE(dirp->dirent);
  1638. }
  1639. NOB_FREE(dirp);
  1640. return 0;
  1641. }
  1642. #endif // _WIN32
  1643. // minirent.h SOURCE END ////////////////////////////////////////
  1644. #endif // NOB_IMPLEMENTATION
  1645. #ifndef NOB_STRIP_PREFIX_GUARD_
  1646. #define NOB_STRIP_PREFIX_GUARD_
  1647. // NOTE: The name stripping should be part of the header so it's not accidentally included
  1648. // several times. At the same time, it should be at the end of the file so to not create any
  1649. // potential conflicts in the NOB_IMPLEMENTATION. The header obviously cannot be at the end
  1650. // of the file because NOB_IMPLEMENTATION needs the forward declarations from there. So the
  1651. // solution is to split the header into two parts where the name stripping part is at the
  1652. // end of the file after the NOB_IMPLEMENTATION.
  1653. #ifdef NOB_STRIP_PREFIX
  1654. #define TODO NOB_TODO
  1655. #define UNREACHABLE NOB_UNREACHABLE
  1656. #define UNUSED NOB_UNUSED
  1657. #define ARRAY_LEN NOB_ARRAY_LEN
  1658. #define ARRAY_GET NOB_ARRAY_GET
  1659. #define INFO NOB_INFO
  1660. #define WARNING NOB_WARNING
  1661. #define ERROR NOB_ERROR
  1662. #define NO_LOGS NOB_NO_LOGS
  1663. #define Log_Level Nob_Log_Level
  1664. #define minimal_log_level nob_minimal_log_level
  1665. // NOTE: Name log is already defined in math.h and historically always was the natural logarithmic function.
  1666. // So there should be no reason to strip the `nob_` prefix in this specific case.
  1667. // #define log nob_log
  1668. #define shift nob_shift
  1669. #define shift_args nob_shift_args
  1670. #define File_Paths Nob_File_Paths
  1671. #define FILE_REGULAR NOB_FILE_REGULAR
  1672. #define FILE_DIRECTORY NOB_FILE_DIRECTORY
  1673. #define FILE_SYMLINK NOB_FILE_SYMLINK
  1674. #define FILE_OTHER NOB_FILE_OTHER
  1675. #define File_Type Nob_File_Type
  1676. #define mkdir_if_not_exists nob_mkdir_if_not_exists
  1677. #define copy_file nob_copy_file
  1678. #define copy_directory_recursively nob_copy_directory_recursively
  1679. #define read_entire_dir nob_read_entire_dir
  1680. #define write_entire_file nob_write_entire_file
  1681. #define get_file_type nob_get_file_type
  1682. #define delete_file nob_delete_file
  1683. #define return_defer nob_return_defer
  1684. #define da_append nob_da_append
  1685. #define da_free nob_da_free
  1686. #define da_append_many nob_da_append_many
  1687. #define da_resize nob_da_resize
  1688. #define da_reserve nob_da_reserve
  1689. #define da_last nob_da_last
  1690. #define da_remove_unordered nob_da_remove_unordered
  1691. #define da_foreach nob_da_foreach
  1692. #define String_Builder Nob_String_Builder
  1693. #define read_entire_file nob_read_entire_file
  1694. #define sb_appendf nob_sb_appendf
  1695. #define sb_append_buf nob_sb_append_buf
  1696. #define sb_append_cstr nob_sb_append_cstr
  1697. #define sb_append_null nob_sb_append_null
  1698. #define sb_free nob_sb_free
  1699. #define Proc Nob_Proc
  1700. #define INVALID_PROC NOB_INVALID_PROC
  1701. #define Fd Nob_Fd
  1702. #define INVALID_FD NOB_INVALID_FD
  1703. #define fd_open_for_read nob_fd_open_for_read
  1704. #define fd_open_for_write nob_fd_open_for_write
  1705. #define fd_close nob_fd_close
  1706. #define Procs Nob_Procs
  1707. #define proc_wait nob_proc_wait
  1708. #define procs_wait nob_procs_wait
  1709. #define procs_wait_and_reset nob_procs_wait_and_reset
  1710. #define procs_append_with_flush nob_procs_append_with_flush
  1711. #define Cmd Nob_Cmd
  1712. #define Cmd_Redirect Nob_Cmd_Redirect
  1713. #define cmd_render nob_cmd_render
  1714. #define cmd_append nob_cmd_append
  1715. #define cmd_extend nob_cmd_extend
  1716. #define cmd_free nob_cmd_free
  1717. #define cmd_run_async nob_cmd_run_async
  1718. #define cmd_run_async_and_reset nob_cmd_run_async_and_reset
  1719. #define cmd_run_async_redirect nob_cmd_run_async_redirect
  1720. #define cmd_run_async_redirect_and_reset nob_cmd_run_async_redirect_and_reset
  1721. #define cmd_run_sync nob_cmd_run_sync
  1722. #define cmd_run_sync_and_reset nob_cmd_run_sync_and_reset
  1723. #define cmd_run_sync_redirect nob_cmd_run_sync_redirect
  1724. #define cmd_run_sync_redirect_and_reset nob_cmd_run_sync_redirect_and_reset
  1725. #define temp_strdup nob_temp_strdup
  1726. #define temp_alloc nob_temp_alloc
  1727. #define temp_sprintf nob_temp_sprintf
  1728. #define temp_reset nob_temp_reset
  1729. #define temp_save nob_temp_save
  1730. #define temp_rewind nob_temp_rewind
  1731. #define path_name nob_path_name
  1732. // NOTE: rename(2) is widely known POSIX function. We never wanna collide with it.
  1733. // #define rename nob_rename
  1734. #define needs_rebuild nob_needs_rebuild
  1735. #define needs_rebuild1 nob_needs_rebuild1
  1736. #define file_exists nob_file_exists
  1737. #define get_current_dir_temp nob_get_current_dir_temp
  1738. #define set_current_dir nob_set_current_dir
  1739. #define String_View Nob_String_View
  1740. #define temp_sv_to_cstr nob_temp_sv_to_cstr
  1741. #define sv_chop_by_delim nob_sv_chop_by_delim
  1742. #define sv_chop_left nob_sv_chop_left
  1743. #define sv_trim nob_sv_trim
  1744. #define sv_trim_left nob_sv_trim_left
  1745. #define sv_trim_right nob_sv_trim_right
  1746. #define sv_eq nob_sv_eq
  1747. #define sv_starts_with nob_sv_starts_with
  1748. #define sv_end_with nob_sv_end_with
  1749. #define sv_from_cstr nob_sv_from_cstr
  1750. #define sv_from_parts nob_sv_from_parts
  1751. #define sb_to_sv nob_sb_to_sv
  1752. #define win32_error_message nob_win32_error_message
  1753. #endif // NOB_STRIP_PREFIX
  1754. #endif // NOB_STRIP_PREFIX_GUARD_
  1755. /*
  1756. Revision history:
  1757. 1.20.6 (2025-05-16) Never strip nob_* suffix from nob_rename (By @rexim)
  1758. 1.20.5 (2025-05-16) NOB_PRINTF_FORMAT() support for MinGW (By @KillerxDBr)
  1759. 1.20.4 (2025-05-16) More reliable rendering of the Windows command (By @vylsaz)
  1760. 1.20.3 (2025-05-16) Add check for __clang__ along with _MSC_VER checks (By @nashiora)
  1761. 1.20.2 (2025-04-24) Report the program name that failed to start up in nob_cmd_run_async_redirect() (By @rexim)
  1762. 1.20.1 (2025-04-16) Use vsnprintf() in nob_sb_appendf() instead of vsprintf() (By @LainLayer)
  1763. 1.20.0 (2025-04-16) Introduce nob_cc(), nob_cc_flags(), nob_cc_inputs(), nob_cc_output() macros (By @rexim)
  1764. 1.19.0 (2025-03-25) Add nob_procs_append_with_flush() (By @rexim and @anion155)
  1765. 1.18.0 (2025-03-24) Add nob_da_foreach() (By @rexim)
  1766. Allow file sizes greater than 2GB to be read on windows (By @satchelfrost and @KillerxDBr)
  1767. Fix nob_fd_open_for_write behaviour on windows so it truncates the opened files (By @twixuss)
  1768. 1.17.0 (2025-03-16) Factor out nob_da_reserve() (By @rexim)
  1769. Add nob_sb_appendf() (By @angelcaru)
  1770. 1.16.1 (2025-03-16) Make nob_da_resize() exponentially grow capacity similar to no_da_append_many()
  1771. 1.16.0 (2025-03-16) Introduce NOB_PRINTF_FORMAT
  1772. 1.15.1 (2025-03-16) Make nob.h compilable in gcc/clang with -std=c99 on POSIX. This includes:
  1773. not using strsignal()
  1774. using S_IS* stat macros instead of S_IF* flags
  1775. 1.15.0 (2025-03-03) Add nob_sv_chop_left()
  1776. 1.14.1 (2025-03-02) Add NOB_EXPERIMENTAL_DELETE_OLD flag that enables deletion of nob.old in Go Rebuild Urself™ Technology
  1777. 1.14.0 (2025-02-17) Add nob_da_last()
  1778. Add nob_da_remove_unordered()
  1779. 1.13.1 (2025-02-17) Fix segfault in nob_delete_file() (By @SileNce5k)
  1780. 1.13.0 (2025-02-11) Add nob_da_resize() (By @satchelfrost)
  1781. 1.12.0 (2025-02-04) Add nob_delete_file()
  1782. Add nob_sv_start_with()
  1783. 1.11.0 (2025-02-04) Add NOB_GO_REBUILD_URSELF_PLUS() (By @rexim)
  1784. 1.10.0 (2025-02-04) Make NOB_ASSERT, NOB_REALLOC, and NOB_FREE redefinable (By @OleksiiBulba)
  1785. 1.9.1 (2025-02-04) Fix signature of nob_get_current_dir_temp() (By @julianstoerig)
  1786. 1.9.0 (2024-11-06) Add Nob_Cmd_Redirect mechanism (By @rexim)
  1787. Add nob_path_name() (By @0dminnimda)
  1788. 1.8.0 (2024-11-03) Add nob_cmd_extend() (By @0dminnimda)
  1789. 1.7.0 (2024-11-03) Add nob_win32_error_message and NOB_WIN32_ERR_MSG_SIZE (By @KillerxDBr)
  1790. 1.6.0 (2024-10-27) Add nob_cmd_run_sync_and_reset()
  1791. Add nob_sb_to_sv()
  1792. Add nob_procs_wait_and_reset()
  1793. 1.5.1 (2024-10-25) Include limits.h for Linux musl libc (by @pgalkin)
  1794. 1.5.0 (2024-10-23) Add nob_get_current_dir_temp()
  1795. Add nob_set_current_dir()
  1796. 1.4.0 (2024-10-21) Fix UX issues with NOB_GO_REBUILD_URSELF on Windows when you call nob without the .exe extension (By @pgalkin)
  1797. Add nob_sv_end_with (By @pgalkin)
  1798. 1.3.2 (2024-10-21) Fix unreachable error in nob_log on passing NOB_NO_LOGS
  1799. 1.3.1 (2024-10-21) Fix redeclaration error for minimal_log_level (By @KillerxDBr)
  1800. 1.3.0 (2024-10-17) Add NOB_UNREACHABLE
  1801. 1.2.2 (2024-10-16) Fix compilation of nob_cmd_run_sync_and_reset on Windows (By @KillerxDBr)
  1802. 1.2.1 (2024-10-16) Add a separate include guard for NOB_STRIP_PREFIX.
  1803. 1.2.0 (2024-10-15) Make NOB_DA_INIT_CAP redefinable
  1804. Add NOB_STRIP_PREFIX which strips off nob_* prefix from all the user facing names
  1805. Add NOB_UNUSED macro
  1806. Add NOB_TODO macro
  1807. Add nob_sv_trim_left and nob_sv_trim_right declarations to the header part
  1808. 1.1.1 (2024-10-15) Remove forward declaration for is_path1_modified_after_path2
  1809. 1.1.0 (2024-10-15) nob_minimal_log_level
  1810. nob_cmd_run_sync_and_reset
  1811. 1.0.0 (2024-10-15) first release based on https://github.com/tsoding/musializer/blob/4ac7cce9874bc19e02d8c160c8c6229de8919401/nob.h
  1812. */
  1813. /*
  1814. Version Conventions:
  1815. We are following https://semver.org/ so the version has a format MAJOR.MINOR.PATCH:
  1816. - Modifying comments does not update the version.
  1817. - PATCH is incremented in case of a bug fix or refactoring without touching the API.
  1818. - MINOR is incremented when new functions and/or types are added in a way that does
  1819. not break any existing user code. We want to do this in the majority of the situation.
  1820. If we want to delete a certain function or type in favor of another one we should
  1821. just add the new function/type and deprecate the old one in a backward compatible way
  1822. and let them co-exist for a while.
  1823. - MAJOR update should be just a periodic cleanup of the deprecated functions and types
  1824. without really modifying any existing functionality.
  1825. Naming Conventions:
  1826. - All the user facing names should be prefixed with `nob_` or `NOB_` depending on the case.
  1827. - The prefixes of non-redefinable names should be strippable with NOB_STRIP_PREFIX (unless
  1828. explicitly stated otherwise like in case of nob_log).
  1829. - Internal functions should be prefixed with `nob__` (double underscore).
  1830. */
  1831. /*
  1832. ------------------------------------------------------------------------------
  1833. This software is available under 2 licenses -- choose whichever you prefer.
  1834. ------------------------------------------------------------------------------
  1835. ALTERNATIVE A - MIT License
  1836. Copyright (c) 2024 Alexey Kutepov
  1837. Permission is hereby granted, free of charge, to any person obtaining a copy of
  1838. this software and associated documentation files (the "Software"), to deal in
  1839. the Software without restriction, including without limitation the rights to
  1840. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  1841. of the Software, and to permit persons to whom the Software is furnished to do
  1842. so, subject to the following conditions:
  1843. The above copyright notice and this permission notice shall be included in all
  1844. copies or substantial portions of the Software.
  1845. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1846. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1847. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1848. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1849. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1850. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  1851. SOFTWARE.
  1852. ------------------------------------------------------------------------------
  1853. ALTERNATIVE B - Public Domain (www.unlicense.org)
  1854. This is free and unencumbered software released into the public domain.
  1855. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
  1856. software, either in source code form or as a compiled binary, for any purpose,
  1857. commercial or non-commercial, and by any means.
  1858. In jurisdictions that recognize copyright laws, the author or authors of this
  1859. software dedicate any and all copyright interest in the software to the public
  1860. domain. We make this dedication for the benefit of the public at large and to
  1861. the detriment of our heirs and successors. We intend this dedication to be an
  1862. overt act of relinquishment in perpetuity of all present and future rights to
  1863. this software under copyright law.
  1864. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1865. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1866. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1867. AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  1868. ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  1869. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1870. ------------------------------------------------------------------------------
  1871. */