title: Redirect printf to fopencookie
body: <p>On Linux (Raspbian on a Raspberry Pi) I would like to make it so that anything my C application prints using <code>printf</code> is sent back to me in a callback.</p>
  
  <p>(No, I'm not talking about shell redirection with <code>&gt; some_file.txt</code>.  I'm talking about a C program making the decision <em>by itself</em> to send <code>stdout</code> (and therefore <code>printf</code>) to a callback within that same program.)</p>
  
  <p>(Yes, I really do want to do this.  I'm making a full-screen program using OpenGL and want to present any <code>printf</code>'d text to the user within that program, using my own rendering code.  Replacing all <code>printf</code> calls with something else is not feasible.)</p>
  
  <p>I feel like this should be easy.  There are variations of this question on StackOverflow already, but none that I could find are exactly the same.</p>
  
  <p>I can use <code>fopencookie</code> to get a <code>FILE*</code> that ends up calling my callback.  So far, so good.  The challenge is to get <code>stdout</code> and <code>printf</code> to go there.</p>
  
  <p>I <em>can't</em> use <code>freopen</code> because it takes a string path.  The <code>FILE*</code> I want to redirect to is not a file on the filesystem but rather just exists at runtime.</p>
  
  <p>I <em>can't</em> use <code>dup2</code> because the <code>FILE*</code> from <code>fopencookie</code> does not have a file descriptor (<code>fileno</code> returns -1).</p>
  
  <p>The <a href="https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html" rel="nofollow noreferrer">glibc documentation</a> suggests that I can simply reassign <code>stdout</code> to my new <code>FILE*</code>: <em>"stdin, stdout, and stderr are normal variables which you can set just like any others."</em>.   This <strong>does almost work</strong>.  Anything printed with <code>fprintf (stdout, "whatever")</code> <em>does</em> go to my callback, and so does any <code>printf</code> that has any format specifiers.  However, any call to <code>printf</code> with a string with  no format specifiers at all still goes to the "original" stdout.</p>
  
  <p>How can I achieve what I'm trying to do?</p>
  
  <p>PS: I don't care about portability.  This will only ever run on my current environment.</p>
  
  <pre><code>#define _GNU_SOURCE                                                         
  #include &lt;stdio.h&gt;                                                          
  #include &lt;unistd.h&gt;                                                         
  #include &lt;assert.h&gt;                                                         
  #include &lt;stdarg.h&gt;                                                         
  #include &lt;alloca.h&gt;                                                         
  #include &lt;string.h&gt;                                                         
  
  
  static ssize_t my_write_func (void * cookie, const char * buf, size_t size) 
  {                                                                           
      fprintf (stderr, "my_write_func received %d bytes\n", size);            
      char * copy = (char*) alloca (size + 1);                                
      assert (copy);                                                          
      copy[size] = 0;                                                         
      strncpy (copy, buf, size);                                              
      fprintf (stderr, "Text is: \"%s\"\n", copy);                            
      fflush (stderr);                                                        
      return size;                                                            
  }                                                                           
  
  
  static FILE * create_opencookie ()                                          
  {                                                                           
      cookie_io_functions_t funcs;                                            
      memset (&amp;funcs, 0, sizeof (funcs));                                     
      funcs.write = my_write_func;                                            
      FILE * f = fopencookie (NULL, "w", funcs);                              
      assert (f);                                                             
      return f;                                                               
  }                                                                           
  
  
  int main (int argc, char ** argv)                                           
  {                                                                           
      FILE * f = create_opencookie ();                                        
      fclose (stdout);                                                        
      stdout = f;                                                             
  
      // These two DO go to my callback:                                                                        
      fprintf (stdout, "This is a long string, fprintf'd to stdout\n");                           
      printf ("Hello world, this is a printf with a digit: %d\n", 123);
  
      // This does not go to my callback.
      // If I omit the fclose above then it gets printed to the console.
      printf ("Hello world, this is plain printf.\n");           
      fflush (NULL);                                                          
      return 0;                                                               
  }               
  </code></pre>