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
fake_file_init_file(FakeFILE * file,FILE * f)9 void fake_file_init_file(FakeFILE* file, FILE* f) {
10 memset(file, 0, sizeof(*file));
11 file->file = f;
12 }
13
fake_file_init_buffer(FakeFILE * file,char * buffer,size_t buffer_size)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
fake_file_init_wbuffer(FakeFILE * file,wchar_t * buffer,size_t buffer_size)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
fake_file_out(FakeFILE * file,const char * text,size_t length)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
fake_file_outw(FakeFILE * file,const wchar_t * text,size_t length)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
fake_feof(FakeFILE * file)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
fake_ferror(FakeFILE * file)79 int fake_ferror(FakeFILE* file) {
80 if (file->file != NULL)
81 return ferror(file->file);
82
83 return 0;
84 }
85
fake_fprintf(FakeFILE * file,const char * format,...)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
fake_fputc(char ch,FakeFILE * file)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
fake_fputwc(wchar_t wc,FakeFILE * file)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