Home | History | Annotate | Download | only in stdio
      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