|
164 | 164 | # include <direct.h> |
165 | 165 | # include <io.h> |
166 | 166 | # include <shellapi.h> |
| 167 | +# include <ConsoleApi.h> |
| 168 | +# include <ConsoleApi2.h> |
167 | 169 | #else |
168 | 170 | # ifdef __APPLE__ |
169 | 171 | # include <mach-o/dyld.h> |
|
202 | 204 | #endif |
203 | 205 |
|
204 | 206 | #define NOB_UNUSED(value) (void)(value) |
205 | | -#define NOB_TODO(message) do { fprintf(stderr, "%s:%d: TODO: %s\n", __FILE__, __LINE__, message); abort(); } while(0) |
206 | | -#define NOB_UNREACHABLE(message) do { fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); abort(); } while(0) |
| 207 | +#define NOB_TODO(message) do { nob__fprintf(stderr, "%s:%d: TODO: %s\n", __FILE__, __LINE__, message); abort(); } while(0) |
| 208 | +#define NOB_UNREACHABLE(message) do { nob__fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); abort(); } while(0) |
207 | 209 |
|
208 | 210 | #define NOB_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0])) |
209 | 211 | #define NOB_ARRAY_GET(array, index) \ |
@@ -874,6 +876,144 @@ void nob__cmd_append(Nob_Cmd *cmd, size_t n, ...) |
874 | 876 | va_end(args); |
875 | 877 | } |
876 | 878 |
|
| 879 | + |
| 880 | +#ifdef _WIN32 |
| 881 | + |
| 882 | + |
| 883 | +WORD nob__unicode_debug_beg(HANDLE win_out) |
| 884 | +{ |
| 885 | +#ifdef NOB_DEBUG_UNIOCDE |
| 886 | + BOOL b; |
| 887 | + CONSOLE_SCREEN_BUFFER_INFO info; |
| 888 | + WORD attributes; |
| 889 | + |
| 890 | + b = GetConsoleScreenBufferInfo(win_out, &info); |
| 891 | + NOB_ASSERT(b != 0); |
| 892 | + attributes = info.wAttributes; |
| 893 | + b = SetConsoleTextAttribute(win_out, FOREGROUND_INTENSITY | FOREGROUND_GREEN); |
| 894 | + NOB_ASSERT(b != 0); |
| 895 | + return attributes; |
| 896 | +#else |
| 897 | + (void)win_out; |
| 898 | + return 0; |
| 899 | +#endif |
| 900 | +} |
| 901 | + |
| 902 | +void nob__unicode_debug_end(HANDLE win_out, WORD attributes) |
| 903 | +{ |
| 904 | +#ifdef NOB_DEBUG_UNIOCDE |
| 905 | + BOOL b; |
| 906 | + |
| 907 | + b = SetConsoleTextAttribute(win_out, attributes); |
| 908 | + NOB_ASSERT(b != 0); |
| 909 | +#else |
| 910 | + (void)win_out; |
| 911 | + (void)attributes; |
| 912 | +#endif |
| 913 | +} |
| 914 | + |
| 915 | +int nob__vfprintf(FILE *stream, const char *format, va_list args) |
| 916 | +{ |
| 917 | + char *narrow_ptr; |
| 918 | + char narrow_buf[1024]; |
| 919 | + size_t narrow_mark; |
| 920 | + int narrow_len_a; |
| 921 | + int narrow_len_b; |
| 922 | + HANDLE win_out; |
| 923 | + DWORD file_type; |
| 924 | + wchar_t *wide_ptr; |
| 925 | + wchar_t wide_buf[1024]; |
| 926 | + size_t wide_mark; |
| 927 | + int wide_len_a; |
| 928 | + DWORD err; |
| 929 | + int wide_len_b; |
| 930 | + WORD revert; |
| 931 | + BOOL b; |
| 932 | + DWORD written; |
| 933 | + |
| 934 | + narrow_ptr = narrow_buf; |
| 935 | + narrow_mark = 0; |
| 936 | + narrow_len_a = vsnprintf(narrow_buf, NOB_ARRAY_LEN(narrow_buf), format, args); |
| 937 | + NOB_ASSERT(narrow_len_a >= 0); /* vsnprintf failed, what now? */ |
| 938 | + if (narrow_len_a >= NOB_ARRAY_LEN(narrow_buf)) { |
| 939 | + narrow_mark = nob_temp_save(); |
| 940 | + narrow_ptr = (char*)nob_temp_alloc(narrow_len_a + 1); |
| 941 | + NOB_ASSERT(narrow_ptr); /* nob_temp_alloc failed, what now? */ |
| 942 | + narrow_len_b = vsnprintf(narrow_ptr, narrow_len_a + 1, format, args); |
| 943 | + NOB_ASSERT(narrow_len_b == narrow_len_a); /* Second call to vsnprintf produced different result thatn first call, what now? */ |
| 944 | + } |
| 945 | + NOB_ASSERT(stream == stdout || stream == stderr); /* It is user error to print to stdin or to non-standard stream. */ |
| 946 | + win_out = GetStdHandle(stream == stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); |
| 947 | + NOB_ASSERT(win_out != INVALID_HANDLE_VALUE); /* GetStdHandle failed, what now? */ |
| 948 | + if (win_out == NULL) { |
| 949 | + return 0; |
| 950 | + } |
| 951 | + file_type = GetFileType(win_out); |
| 952 | + if (file_type == FILE_TYPE_CHAR) { |
| 953 | + wide_ptr = wide_buf; |
| 954 | + wide_mark = 0; |
| 955 | + wide_len_a = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, narrow_ptr, narrow_len_a, wide_buf, NOB_ARRAY_LEN(wide_buf)); |
| 956 | + err = GetLastError(); |
| 957 | + NOB_ASSERT((wide_len_a != 0) || (wide_len_a == 0 && err == ERROR_INSUFFICIENT_BUFFER)); /* MultiByteToWideChar failed, what now? */ |
| 958 | + if (wide_len_a == 0 && err == ERROR_INSUFFICIENT_BUFFER) { |
| 959 | + wide_len_a = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, narrow_ptr, narrow_len_a, NULL, 0); |
| 960 | + NOB_ASSERT(wide_len_a > NOB_ARRAY_LEN(wide_buf)); /* MultiByteToWideChar failed, what now? */ |
| 961 | + wide_mark = nob_temp_save(); |
| 962 | + wide_ptr = (wchar_t*)nob_temp_alloc(wide_len_a * sizeof(wchar_t)); |
| 963 | + NOB_ASSERT(wide_ptr); /* nob_temp_alloc failed, what now? */ |
| 964 | + wide_len_b = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, narrow_ptr, narrow_len_a, wide_ptr, wide_len_a); |
| 965 | + NOB_ASSERT(wide_len_b == wide_len_a); /* MultiByteToWideChar failed, what now? */ |
| 966 | + } |
| 967 | + revert = nob__unicode_debug_beg(win_out); |
| 968 | + b = WriteConsoleW(win_out, wide_ptr, (DWORD)wide_len_a, &written, NULL); |
| 969 | + nob__unicode_debug_end(win_out, revert); |
| 970 | + NOB_ASSERT(b != 0); /* WriteConsoleW failed, what now? */ |
| 971 | + NOB_ASSERT(written == (DWORD)wide_len_a); /* WriteConsoleW failed, what now? */ |
| 972 | + if (wide_ptr != wide_buf) { |
| 973 | + nob_temp_rewind(wide_mark); |
| 974 | + } |
| 975 | + } else { |
| 976 | + b = WriteFile(win_out, narrow_ptr, (DWORD)narrow_len_a, &written, NULL); |
| 977 | + NOB_ASSERT(b != 0); /* WriteFile failed, what now? */ |
| 978 | + NOB_ASSERT(written == (DWORD)narrow_len_a); /* WriteFile failed, what now? */ |
| 979 | + } |
| 980 | + if (narrow_ptr != narrow_buf) { |
| 981 | + nob_temp_rewind(narrow_mark); |
| 982 | + } |
| 983 | + return narrow_len_a; |
| 984 | +} |
| 985 | + |
| 986 | +int nob__fprintf(FILE *stream, const char *fmt, ...) |
| 987 | +{ |
| 988 | + va_list args; |
| 989 | + int len; |
| 990 | + |
| 991 | + va_start(args, fmt); |
| 992 | + len = nob__vfprintf(stream, fmt, args); |
| 993 | + va_end(args); |
| 994 | + return len; |
| 995 | +} |
| 996 | + |
| 997 | +int nob__printf(const char *fmt, ...) |
| 998 | +{ |
| 999 | + va_list args; |
| 1000 | + int len; |
| 1001 | + |
| 1002 | + va_start(args, fmt); |
| 1003 | + len = nob__vfprintf(stdout, fmt, args); |
| 1004 | + va_end(args); |
| 1005 | + return len; |
| 1006 | +} |
| 1007 | + |
| 1008 | +#else |
| 1009 | + |
| 1010 | +#define nob__vfprintf vfprintf |
| 1011 | +#define nob__fprintf fprintf |
| 1012 | +#define nob__printf printf |
| 1013 | + |
| 1014 | +#endif // _WIN32 |
| 1015 | + |
| 1016 | + |
877 | 1017 | #ifdef _WIN32 |
878 | 1018 |
|
879 | 1019 |
|
@@ -1738,42 +1878,42 @@ NOBDEF void nob_default_log_handler(Nob_Log_Level level, const char *fmt, va_lis |
1738 | 1878 |
|
1739 | 1879 | switch (level) { |
1740 | 1880 | case NOB_INFO: |
1741 | | - fprintf(stderr, "[INFO] "); |
| 1881 | + nob__fprintf(stderr, "[INFO] "); |
1742 | 1882 | break; |
1743 | 1883 | case NOB_WARNING: |
1744 | | - fprintf(stderr, "[WARNING] "); |
| 1884 | + nob__fprintf(stderr, "[WARNING] "); |
1745 | 1885 | break; |
1746 | 1886 | case NOB_ERROR: |
1747 | | - fprintf(stderr, "[ERROR] "); |
| 1887 | + nob__fprintf(stderr, "[ERROR] "); |
1748 | 1888 | break; |
1749 | 1889 | case NOB_NO_LOGS: return; |
1750 | 1890 | default: |
1751 | 1891 | NOB_UNREACHABLE("Nob_Log_Level"); |
1752 | 1892 | } |
1753 | 1893 |
|
1754 | | - vfprintf(stderr, fmt, args); |
1755 | | - fprintf(stderr, "\n"); |
| 1894 | + nob__vfprintf(stderr, fmt, args); |
| 1895 | + nob__fprintf(stderr, "\n"); |
1756 | 1896 | } |
1757 | 1897 |
|
1758 | 1898 | NOBDEF void nob_cancer_log_handler(Nob_Log_Level level, const char *fmt, va_list args) |
1759 | 1899 | { |
1760 | 1900 | switch (level) { |
1761 | 1901 | case NOB_INFO: |
1762 | | - fprintf(stderr, "ℹ️ \x1b[36m[INFO]\x1b[0m "); |
| 1902 | + nob__fprintf(stderr, "ℹ️ \x1b[36m[INFO]\x1b[0m "); |
1763 | 1903 | break; |
1764 | 1904 | case NOB_WARNING: |
1765 | | - fprintf(stderr, "⚠️ \x1b[33m[WARNING]\x1b[0m "); |
| 1905 | + nob__fprintf(stderr, "⚠️ \x1b[33m[WARNING]\x1b[0m "); |
1766 | 1906 | break; |
1767 | 1907 | case NOB_ERROR: |
1768 | | - fprintf(stderr, "🚨 \x1b[31m[ERROR]\x1b[0m "); |
| 1908 | + nob__fprintf(stderr, "🚨 \x1b[31m[ERROR]\x1b[0m "); |
1769 | 1909 | break; |
1770 | 1910 | case NOB_NO_LOGS: return; |
1771 | 1911 | default: |
1772 | 1912 | NOB_UNREACHABLE("Nob_Log_Level"); |
1773 | 1913 | } |
1774 | 1914 |
|
1775 | | - vfprintf(stderr, fmt, args); |
1776 | | - fprintf(stderr, "\n"); |
| 1915 | + nob__vfprintf(stderr, fmt, args); |
| 1916 | + nob__fprintf(stderr, "\n"); |
1777 | 1917 | } |
1778 | 1918 |
|
1779 | 1919 | NOBDEF void nob_log(Nob_Log_Level level, const char *fmt, ...) |
@@ -2787,7 +2927,7 @@ NOBDEF char *nob_temp_running_executable_path(void) |
2787 | 2927 | break; |
2788 | 2928 | return nob_temp_strndup(info.name, strlen(info.name)); |
2789 | 2929 | #else |
2790 | | - fprintf(stderr, "%s:%d: TODO: nob_temp_running_executable_path is not implemented for this platform\n", __FILE__, __LINE__); |
| 2930 | + nob__fprintf(stderr, "%s:%d: TODO: nob_temp_running_executable_path is not implemented for this platform\n", __FILE__, __LINE__); |
2791 | 2931 | return nob_temp_strdup(""); |
2792 | 2932 | #endif |
2793 | 2933 | } |
|
0 commit comments