1- /* nob - v1.25.1 - Public Domain - https://github.com/tsoding/nob.h
1+ /* nob - v1.26.0 - Public Domain - https://github.com/tsoding/nob.h
22
33 This library is the next generation of the [NoBuild](https://github.com/tsoding/nobuild) idea.
44
100100#ifndef NOB_H_
101101#define NOB_H_
102102#ifdef _WIN32
103- #define _CRT_SECURE_NO_WARNINGS (1)
104- #endif
103+ # ifndef _CRT_SECURE_NO_WARNINGS
104+ # define _CRT_SECURE_NO_WARNINGS (1)
105+ # endif // _CRT_SECURE_NO_WARNINGS
106+ #endif // _WIN32
105107
106108#ifndef NOBDEF
107109/*
@@ -207,6 +209,14 @@ typedef enum {
207209// Any messages with the level below nob_minimal_log_level are going to be suppressed.
208210extern Nob_Log_Level nob_minimal_log_level ;
209211
212+ typedef void (nob_log_handler )(Nob_Log_Level level , const char * fmt , va_list args );
213+
214+ NOBDEF void nob_set_log_handler (nob_log_handler * handler );
215+ NOBDEF nob_log_handler * nob_get_log_handler (void );
216+
217+ NOBDEF nob_log_handler nob_default_log_handler ;
218+ NOBDEF nob_log_handler nob_cancer_log_handler ;
219+
210220NOBDEF void nob_log (Nob_Log_Level level , const char * fmt , ...) NOB_PRINTF_FORMAT (2 , 3 );
211221
212222// It is an equivalent of shift command from bash (do `help shift` in bash). It basically
@@ -541,6 +551,7 @@ NOBDEF char *nob_temp_strdup(const char *cstr);
541551NOBDEF char * nob_temp_strndup (const char * cstr , size_t size );
542552NOBDEF void * nob_temp_alloc (size_t size );
543553NOBDEF char * nob_temp_sprintf (const char * format , ...) NOB_PRINTF_FORMAT (1 , 2 );
554+ NOBDEF char * nob_temp_vsprintf (const char * format , va_list ap );
544555// nob_temp_reset() - Resets the entire temporary storage to 0.
545556//
546557// It is generally not recommended to call this function ever. What you usually want to do is let's say you have a loop,
@@ -1143,8 +1154,8 @@ static Nob_Proc nob__cmd_start_process(Nob_Cmd cmd, Nob_Fd *fdin, Nob_Fd *fdout,
11431154 return NOB_INVALID_PROC ;
11441155 }
11451156
1146- #ifndef NOB_NO_ECHO
11471157 Nob_String_Builder sb = {0 };
1158+ #ifndef NOB_NO_ECHO
11481159 nob_cmd_render (cmd , & sb );
11491160 nob_sb_append_null (& sb );
11501161 nob_log (NOB_INFO , "CMD: %s" , sb .items );
@@ -1535,7 +1546,19 @@ NOBDEF bool nob_cmd_run_sync_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect r
15351546 return nob_proc_wait (p );
15361547}
15371548
1538- NOBDEF void nob_log (Nob_Log_Level level , const char * fmt , ...)
1549+ static nob_log_handler * nob__log_handler = & nob_default_log_handler ;
1550+
1551+ NOBDEF void nob_set_log_handler (nob_log_handler * handler )
1552+ {
1553+ nob__log_handler = handler ;
1554+ }
1555+
1556+ NOBDEF nob_log_handler * nob_get_log_handler (void )
1557+ {
1558+ return nob__log_handler ;
1559+ }
1560+
1561+ NOBDEF void nob_default_log_handler (Nob_Log_Level level , const char * fmt , va_list args )
15391562{
15401563 if (level < nob_minimal_log_level ) return ;
15411564
@@ -1551,14 +1574,40 @@ NOBDEF void nob_log(Nob_Log_Level level, const char *fmt, ...)
15511574 break ;
15521575 case NOB_NO_LOGS : return ;
15531576 default :
1554- NOB_UNREACHABLE ("nob_log " );
1577+ NOB_UNREACHABLE ("Nob_Log_Level " );
15551578 }
15561579
1580+ vfprintf (stderr , fmt , args );
1581+ fprintf (stderr , "\n" );
1582+ }
1583+
1584+ NOBDEF void nob_cancer_log_handler (Nob_Log_Level level , const char * fmt , va_list args )
1585+ {
1586+ switch (level ) {
1587+ case NOB_INFO :
1588+ fprintf (stderr , "ℹ️ \x1b[36m[INFO]\x1b[0m " );
1589+ break ;
1590+ case NOB_WARNING :
1591+ fprintf (stderr , "⚠️ \x1b[33m[WARNING]\x1b[0m " );
1592+ break ;
1593+ case NOB_ERROR :
1594+ fprintf (stderr , "🚨 \x1b[31m[ERROR]\x1b[0m " );
1595+ break ;
1596+ case NOB_NO_LOGS : return ;
1597+ default :
1598+ NOB_UNREACHABLE ("Nob_Log_Level" );
1599+ }
1600+
1601+ vfprintf (stderr , fmt , args );
1602+ fprintf (stderr , "\n" );
1603+ }
1604+
1605+ NOBDEF void nob_log (Nob_Log_Level level , const char * fmt , ...)
1606+ {
15571607 va_list args ;
15581608 va_start (args , fmt );
1559- vfprintf ( stderr , fmt , args );
1609+ nob__log_handler ( level , fmt , args );
15601610 va_end (args );
1561- fprintf (stderr , "\n" );
15621611}
15631612
15641613NOBDEF bool nob_read_entire_dir (const char * parent , Nob_File_Paths * children )
@@ -1770,24 +1819,33 @@ NOBDEF void *nob_temp_alloc(size_t requested_size)
17701819 return result ;
17711820}
17721821
1773- NOBDEF char * nob_temp_sprintf (const char * format , ... )
1822+ NOBDEF char * nob_temp_vsprintf (const char * format , va_list ap )
17741823{
17751824 va_list args ;
1776- va_start (args , format );
1825+ va_copy (args , ap );
17771826 int n = vsnprintf (NULL , 0 , format , args );
17781827 va_end (args );
17791828
17801829 NOB_ASSERT (n >= 0 );
17811830 char * result = (char * )nob_temp_alloc (n + 1 );
17821831 NOB_ASSERT (result != NULL && "Extend the size of the temporary allocator" );
17831832 // TODO: use proper arenas for the temporary allocator;
1784- va_start (args , format );
1833+ va_copy (args , ap );
17851834 vsnprintf (result , n + 1 , format , args );
17861835 va_end (args );
17871836
17881837 return result ;
17891838}
17901839
1840+ NOBDEF char * nob_temp_sprintf (const char * format , ...)
1841+ {
1842+ va_list args ;
1843+ va_start (args , format );
1844+ char * result = nob_temp_vsprintf (format , args );
1845+ va_end (args );
1846+ return result ;
1847+ }
1848+
17911849NOBDEF void nob_temp_reset (void )
17921850{
17931851 nob_temp_size = 0 ;
@@ -2341,6 +2399,11 @@ NOBDEF int closedir(DIR *dirp)
23412399 #define NO_LOGS NOB_NO_LOGS
23422400 #define Log_Level Nob_Log_Level
23432401 #define minimal_log_level nob_minimal_log_level
2402+ #define log_handler nob_log_handler
2403+ #define set_log_handler nob_set_log_handler
2404+ #define get_log_handler nob_get_log_handler
2405+ #define default_log_handler nob_default_log_handler
2406+ #define cancer_log_handler nob_cancer_log_handler
23442407 // NOTE: Name log is already defined in math.h and historically always was the natural logarithmic function.
23452408 // So there should be no reason to strip the `nob_` prefix in this specific case.
23462409 // #define log nob_log
@@ -2411,6 +2474,7 @@ NOBDEF int closedir(DIR *dirp)
24112474 #define temp_strndup nob_temp_strndup
24122475 #define temp_alloc nob_temp_alloc
24132476 #define temp_sprintf nob_temp_sprintf
2477+ #define temp_vsprintf nob_temp_vsprintf
24142478 #define temp_reset nob_temp_reset
24152479 #define temp_save nob_temp_save
24162480 #define temp_rewind nob_temp_rewind
@@ -2449,7 +2513,16 @@ NOBDEF int closedir(DIR *dirp)
24492513/*
24502514 Revision history:
24512515
2452- 1.25.1 (2025-11-06) Fix forward declaration of _NSGetExecutablePath on MacOS (by agss0)
2516+ 1.26.0 (2025-12-28) Introduce customizable log handlers (by @rexim)
2517+ - Add nob_log_handler
2518+ - Add nob_set_log_handler
2519+ - Add nob_get_log_handler
2520+ - Add nob_default_log_handler
2521+ - Add nob_cancer_log_handler
2522+ Introduce nob_temp_vsprintf (by @rexim)
2523+ Fix compilation error on Windows when NOB_NO_ECHO is enabled (by @mlorenc227)
2524+ Do not redefine _CRT_SECURE_NO_WARNINGS if it's already defined (by @vylsaz)
2525+ 1.25.1 (2025-11-06) Fix forward declaration of _NSGetExecutablePath on MacOS (by @agss0)
24532526 1.25.0 (2025-10-25) - Add nob_sb_pad_align()
24542527 - Add nob_swap()
24552528 - Add nob_temp_strndup()
0 commit comments