Function: write_utf8_cstr_to_stdout(const char *) -> writes a string to standard output; taking into account that on Windows to display correctly you have to use special handling. Works even if the user has not set a unicode code page on a Windows cmd.exe. In case of invalid UTF-8, invalid_utf8 is set to true on Windows, and something a human-readable is written instead. On n
| 130 | // |
| 131 | // On non-Windows systems, simply printfs() the string. |
| 132 | static void write_utf8_cstr_to_stdout(const char * str, bool & invalid_utf8) { |
| 133 | invalid_utf8 = false; |
| 134 | |
| 135 | #if defined(_WIN32) |
| 136 | // Are we in a console? |
| 137 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); |
| 138 | DWORD dwMode = 0; |
| 139 | |
| 140 | // According to Microsoft docs: |
| 141 | // "WriteConsole fails if it is used with a standard handle that is redirected to a file." |
| 142 | // Also according to the docs, you can use GetConsoleMode to check for that. |
| 143 | if (hConsole == INVALID_HANDLE_VALUE || !GetConsoleMode(hConsole, &dwMode)) { |
| 144 | printf("%s", str); |
| 145 | return; |
| 146 | } |
| 147 | |
| 148 | // MultiByteToWideChar reports an error if str is empty, don't report |
| 149 | // them as invalid_utf8. |
| 150 | if (*str == 0) { |
| 151 | return; |
| 152 | } |
| 153 | int length_needed = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, strlen(str), NULL, 0); |
| 154 | if (length_needed == 0) { |
| 155 | DWORD err = GetLastError(); |
| 156 | if (err == ERROR_NO_UNICODE_TRANSLATION) { |
| 157 | invalid_utf8 = true; |
| 158 | int len = strlen(str); |
| 159 | printf("<"); |
| 160 | for (int i = 0; i < len; ++i) { |
| 161 | if (i > 0) { |
| 162 | printf(" "); |
| 163 | } |
| 164 | printf("%02x", (uint8_t) str[i]); |
| 165 | } |
| 166 | printf(">"); |
| 167 | return; |
| 168 | } |
| 169 | GGML_ABORT("MultiByteToWideChar() failed in an unexpected way."); |
| 170 | } |
| 171 | |
| 172 | LPWSTR wstr = (LPWSTR) calloc(length_needed+1, sizeof(*wstr)); |
| 173 | GGML_ASSERT(wstr); |
| 174 | |
| 175 | MultiByteToWideChar(CP_UTF8, 0, str, strlen(str), wstr, length_needed); |
| 176 | WriteConsoleW(hConsole, wstr, length_needed, NULL, NULL); |
| 177 | |
| 178 | free(wstr); |
| 179 | #else |
| 180 | // TODO: reporting invalid_utf8 would be useful on non-Windows too. |
| 181 | // printf will silently just write bad unicode. |
| 182 | printf("%s", str); |
| 183 | #endif |
| 184 | } |
| 185 | |
| 186 | int main(int raw_argc, char ** raw_argv) { |
| 187 | const std::vector<std::string> argv = ingest_args(raw_argc, raw_argv); |