1 #include <stdio.h> 2 #include <wchar.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 #define _STDIO_IMPL_NO_REDIRECT_MACROS 7 #include "stdio_impl.h" 8 9 void fake_file_init_file(FakeFILE* file, FILE* f) { 10 memset(file, 0, sizeof(*file)); 11 file->file = f; 12 } 13 14 void fake_file_init_buffer(FakeFILE* file, char* buffer, size_t buffer_size) { 15 memset(file, 0, sizeof(*file)); 16 file->buffer = (void*)buffer; 17 file->buffer_pos = 0; 18 file->buffer_size = buffer_size; 19 } 20 21 void fake_file_init_wbuffer(FakeFILE* file, 22 wchar_t* buffer, 23 size_t buffer_size) { 24 fake_file_init_buffer(file, (char*)buffer, buffer_size * sizeof(wchar_t)); 25 } 26 27 void fake_file_out(FakeFILE* file, const char* text, size_t length) { 28 if (length == 0) { 29 // Happens pretty often, so bail immediately. 30 return; 31 } 32 if (file->file != NULL) { 33 fwrite(text, 1, length, file->file); 34 } else { 35 // Write into a bounded buffer. 36 size_t avail = file->buffer_size - file->buffer_pos; 37 if (length > avail) 38 length = avail; 39 memcpy((char*)(file->buffer + file->buffer_pos), 40 (const char*)text, 41 length); 42 file->buffer_pos += length; 43 } 44 } 45 46 void fake_file_outw(FakeFILE* file, const wchar_t* text, size_t length) { 47 if (length == 0) 48 return; 49 if (file->file != NULL) { 50 // Write into a file the UTF-8 encoded version. 51 // Original source calls fputwc() in a loop, which is slightly inefficient 52 // for large strings. 53 // TODO(digit): Support locale-specific encoding? 54 size_t mb_len = wcstombs(NULL, text, length); 55 char* mb_buffer = malloc(mb_len); 56 wcstombs(mb_buffer, text, length); 57 fwrite(mb_buffer, 1, mb_len, file->file); 58 free(mb_buffer); 59 } else { 60 // Write into a bounded buffer. This assumes the buffer really 61 // holds wchar_t items. 62 size_t avail = (file->buffer_size - file->buffer_pos) / sizeof(wchar_t); 63 if (length > avail) 64 length = avail; 65 memcpy((char*)(file->buffer + file->buffer_pos), 66 (const char*)text, 67 length * sizeof(wchar_t)); 68 file->buffer_pos += length * sizeof(wchar_t); 69 } 70 } 71 72 int fake_feof(FakeFILE* file) { 73 if (file->file != NULL) 74 return feof(file->file); 75 else 76 return (file->buffer_pos >= file->buffer_size); 77 } 78 79 int fake_ferror(FakeFILE* file) { 80 if (file->file != NULL) 81 return ferror(file->file); 82 83 return 0; 84 } 85 86 int fake_fprintf(FakeFILE* file, const char* format, ...) { 87 va_list args; 88 va_start(args, format); 89 if (file->file) 90 return vfprintf(file->file, format, args); 91 else { 92 // TODO(digit): Make this faster. 93 // First, generate formatted byte output. 94 int mb_len = vsnprintf(NULL, 0, format, args); 95 char* mb_buffer = malloc(mb_len + 1); 96 vsnprintf(mb_buffer, mb_len + 1, format, args); 97 // Then convert to wchar_t buffer. 98 size_t wide_len = mbstowcs(NULL, mb_buffer, mb_len); 99 wchar_t* wide_buffer = malloc((wide_len + 1) * sizeof(wchar_t)); 100 mbstowcs(wide_buffer, mb_buffer, mb_len); 101 // Add to buffer. 102 fake_file_outw(file, wide_buffer, wide_len); 103 // finished 104 free(wide_buffer); 105 free(mb_buffer); 106 107 return wide_len; 108 } 109 va_end(args); 110 } 111 112 void fake_fputc(char ch, FakeFILE* file) { 113 if (file->file) 114 fputc(ch, file->file); 115 else { 116 if (file->buffer_pos < file->buffer_size) 117 file->buffer[file->buffer_pos++] = ch; 118 } 119 } 120 121 void fake_fputwc(wchar_t wc, FakeFILE* file) { 122 if (file->file) 123 fputwc(wc, file->file); 124 else { 125 if (file->buffer_pos + sizeof(wchar_t) - 1U < file->buffer_size) { 126 *(wchar_t*)(&file->buffer[file->buffer_pos]) = wc; 127 file->buffer_pos += sizeof(wchar_t); 128 } 129 } 130 } 131