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