Redirect printf to fopencookie












3















On Linux (Raspbian on a Raspberry Pi) I would like to make it so that anything my C application prints using printf is sent back to me in a callback.



(No, I'm not talking about shell redirection with > some_file.txt. I'm talking about a C program making the decision by itself to send stdout (and therefore printf) to a callback within that same program.)



(Yes, I really do want to do this. I'm making a full-screen program using OpenGL and want to present any printf'd text to the user within that program, using my own rendering code. Replacing all printf calls with something else is not feasible.)



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.



I can use fopencookie to get a FILE* that ends up calling my callback. So far, so good. The challenge is to get stdout and printf to go there.



I can't use freopen because it takes a string path. The FILE* I want to redirect to is not a file on the filesystem but rather just exists at runtime.



I can't use dup2 because the FILE* from fopencookie does not have a file descriptor (fileno returns -1).



The glibc documentation suggests that I can simply reassign stdout to my new FILE*: "stdin, stdout, and stderr are normal variables which you can set just like any others.". This does almost work. Anything printed with fprintf (stdout, "whatever") does go to my callback, and so does any printf that has any format specifiers. However, any call to printf with a string with no format specifiers at all still goes to the "original" stdout.



How can I achieve what I'm trying to do?



PS: I don't care about portability. This will only ever run on my current environment.



#define _GNU_SOURCE                                                         
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>


static ssize_t my_write_func (void * cookie, const char * buf, size_t size)
{
fprintf (stderr, "my_write_func received %d bytesn", 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 (&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 stdoutn");
printf ("Hello world, this is a printf with a digit: %dn", 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;
}









share|improve this question


















  • 1





    Sounds like an issue with the glibc printf extension. Have you considered just using #define printf cookie_printf or something to that effect. It's pretty easy to write your own function that has the same signature as printf that then calls vfprintf. stackoverflow.com/a/1737675/1028434

    – Fred
    Dec 30 '18 at 18:47
















3















On Linux (Raspbian on a Raspberry Pi) I would like to make it so that anything my C application prints using printf is sent back to me in a callback.



(No, I'm not talking about shell redirection with > some_file.txt. I'm talking about a C program making the decision by itself to send stdout (and therefore printf) to a callback within that same program.)



(Yes, I really do want to do this. I'm making a full-screen program using OpenGL and want to present any printf'd text to the user within that program, using my own rendering code. Replacing all printf calls with something else is not feasible.)



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.



I can use fopencookie to get a FILE* that ends up calling my callback. So far, so good. The challenge is to get stdout and printf to go there.



I can't use freopen because it takes a string path. The FILE* I want to redirect to is not a file on the filesystem but rather just exists at runtime.



I can't use dup2 because the FILE* from fopencookie does not have a file descriptor (fileno returns -1).



The glibc documentation suggests that I can simply reassign stdout to my new FILE*: "stdin, stdout, and stderr are normal variables which you can set just like any others.". This does almost work. Anything printed with fprintf (stdout, "whatever") does go to my callback, and so does any printf that has any format specifiers. However, any call to printf with a string with no format specifiers at all still goes to the "original" stdout.



How can I achieve what I'm trying to do?



PS: I don't care about portability. This will only ever run on my current environment.



#define _GNU_SOURCE                                                         
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>


static ssize_t my_write_func (void * cookie, const char * buf, size_t size)
{
fprintf (stderr, "my_write_func received %d bytesn", 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 (&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 stdoutn");
printf ("Hello world, this is a printf with a digit: %dn", 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;
}









share|improve this question


















  • 1





    Sounds like an issue with the glibc printf extension. Have you considered just using #define printf cookie_printf or something to that effect. It's pretty easy to write your own function that has the same signature as printf that then calls vfprintf. stackoverflow.com/a/1737675/1028434

    – Fred
    Dec 30 '18 at 18:47














3












3








3








On Linux (Raspbian on a Raspberry Pi) I would like to make it so that anything my C application prints using printf is sent back to me in a callback.



(No, I'm not talking about shell redirection with > some_file.txt. I'm talking about a C program making the decision by itself to send stdout (and therefore printf) to a callback within that same program.)



(Yes, I really do want to do this. I'm making a full-screen program using OpenGL and want to present any printf'd text to the user within that program, using my own rendering code. Replacing all printf calls with something else is not feasible.)



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.



I can use fopencookie to get a FILE* that ends up calling my callback. So far, so good. The challenge is to get stdout and printf to go there.



I can't use freopen because it takes a string path. The FILE* I want to redirect to is not a file on the filesystem but rather just exists at runtime.



I can't use dup2 because the FILE* from fopencookie does not have a file descriptor (fileno returns -1).



The glibc documentation suggests that I can simply reassign stdout to my new FILE*: "stdin, stdout, and stderr are normal variables which you can set just like any others.". This does almost work. Anything printed with fprintf (stdout, "whatever") does go to my callback, and so does any printf that has any format specifiers. However, any call to printf with a string with no format specifiers at all still goes to the "original" stdout.



How can I achieve what I'm trying to do?



PS: I don't care about portability. This will only ever run on my current environment.



#define _GNU_SOURCE                                                         
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>


static ssize_t my_write_func (void * cookie, const char * buf, size_t size)
{
fprintf (stderr, "my_write_func received %d bytesn", 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 (&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 stdoutn");
printf ("Hello world, this is a printf with a digit: %dn", 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;
}









share|improve this question














On Linux (Raspbian on a Raspberry Pi) I would like to make it so that anything my C application prints using printf is sent back to me in a callback.



(No, I'm not talking about shell redirection with > some_file.txt. I'm talking about a C program making the decision by itself to send stdout (and therefore printf) to a callback within that same program.)



(Yes, I really do want to do this. I'm making a full-screen program using OpenGL and want to present any printf'd text to the user within that program, using my own rendering code. Replacing all printf calls with something else is not feasible.)



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.



I can use fopencookie to get a FILE* that ends up calling my callback. So far, so good. The challenge is to get stdout and printf to go there.



I can't use freopen because it takes a string path. The FILE* I want to redirect to is not a file on the filesystem but rather just exists at runtime.



I can't use dup2 because the FILE* from fopencookie does not have a file descriptor (fileno returns -1).



The glibc documentation suggests that I can simply reassign stdout to my new FILE*: "stdin, stdout, and stderr are normal variables which you can set just like any others.". This does almost work. Anything printed with fprintf (stdout, "whatever") does go to my callback, and so does any printf that has any format specifiers. However, any call to printf with a string with no format specifiers at all still goes to the "original" stdout.



How can I achieve what I'm trying to do?



PS: I don't care about portability. This will only ever run on my current environment.



#define _GNU_SOURCE                                                         
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>


static ssize_t my_write_func (void * cookie, const char * buf, size_t size)
{
fprintf (stderr, "my_write_func received %d bytesn", 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 (&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 stdoutn");
printf ("Hello world, this is a printf with a digit: %dn", 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;
}






c printf raspbian glibc stdio






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 30 '18 at 18:03









peterpipeterpi

385111




385111








  • 1





    Sounds like an issue with the glibc printf extension. Have you considered just using #define printf cookie_printf or something to that effect. It's pretty easy to write your own function that has the same signature as printf that then calls vfprintf. stackoverflow.com/a/1737675/1028434

    – Fred
    Dec 30 '18 at 18:47














  • 1





    Sounds like an issue with the glibc printf extension. Have you considered just using #define printf cookie_printf or something to that effect. It's pretty easy to write your own function that has the same signature as printf that then calls vfprintf. stackoverflow.com/a/1737675/1028434

    – Fred
    Dec 30 '18 at 18:47








1




1





Sounds like an issue with the glibc printf extension. Have you considered just using #define printf cookie_printf or something to that effect. It's pretty easy to write your own function that has the same signature as printf that then calls vfprintf. stackoverflow.com/a/1737675/1028434

– Fred
Dec 30 '18 at 18:47





Sounds like an issue with the glibc printf extension. Have you considered just using #define printf cookie_printf or something to that effect. It's pretty easy to write your own function that has the same signature as printf that then calls vfprintf. stackoverflow.com/a/1737675/1028434

– Fred
Dec 30 '18 at 18:47












1 Answer
1






active

oldest

votes


















5














This appears to be a bug in GLIBC.



The reason that printf("simple string") works differently from printf("foo %d", 123) is that GCC transforms the former into a puts, with the notion that they are equivalent.



As far as I can tell, they should be equivalent. This man page states that puts outputs to stdout, just like printf does.



However, in GLIBC printf outputs to stdout here, but puts outputs to _IO_stdout here, and these are not equivalent. This has already been reported as a glibc bug (upstream bug).



To work around this bug, you could build with -fno-builtin-printf flag. That prevents GCC from transforming printf into puts, and on my system produces:



$ ./a.out
my_write_func received 126 bytes
Text is: "This is a long string, fprintf'd to stdout
Hello world, this is a printf with a digit: 123
Hello world, this is plain printf.
"


This workaround is of course incomplete: if you call puts directly, or link in object files that call printf("simple string") and were not compiled with -fno-builtin-printf (perhaps from 3rd-party library), then you'll still have a problem.



Unfortunately you can't assign to _IO_stdout (which is a macro). The only other thing you could do (that I can think of) is link in your own puts, which just returns printf("%s", arg). That should work if you are linking against libc.so.6, but may cause trouble if you link against libc.a.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53980112%2fredirect-printf-to-fopencookie%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    This appears to be a bug in GLIBC.



    The reason that printf("simple string") works differently from printf("foo %d", 123) is that GCC transforms the former into a puts, with the notion that they are equivalent.



    As far as I can tell, they should be equivalent. This man page states that puts outputs to stdout, just like printf does.



    However, in GLIBC printf outputs to stdout here, but puts outputs to _IO_stdout here, and these are not equivalent. This has already been reported as a glibc bug (upstream bug).



    To work around this bug, you could build with -fno-builtin-printf flag. That prevents GCC from transforming printf into puts, and on my system produces:



    $ ./a.out
    my_write_func received 126 bytes
    Text is: "This is a long string, fprintf'd to stdout
    Hello world, this is a printf with a digit: 123
    Hello world, this is plain printf.
    "


    This workaround is of course incomplete: if you call puts directly, or link in object files that call printf("simple string") and were not compiled with -fno-builtin-printf (perhaps from 3rd-party library), then you'll still have a problem.



    Unfortunately you can't assign to _IO_stdout (which is a macro). The only other thing you could do (that I can think of) is link in your own puts, which just returns printf("%s", arg). That should work if you are linking against libc.so.6, but may cause trouble if you link against libc.a.






    share|improve this answer






























      5














      This appears to be a bug in GLIBC.



      The reason that printf("simple string") works differently from printf("foo %d", 123) is that GCC transforms the former into a puts, with the notion that they are equivalent.



      As far as I can tell, they should be equivalent. This man page states that puts outputs to stdout, just like printf does.



      However, in GLIBC printf outputs to stdout here, but puts outputs to _IO_stdout here, and these are not equivalent. This has already been reported as a glibc bug (upstream bug).



      To work around this bug, you could build with -fno-builtin-printf flag. That prevents GCC from transforming printf into puts, and on my system produces:



      $ ./a.out
      my_write_func received 126 bytes
      Text is: "This is a long string, fprintf'd to stdout
      Hello world, this is a printf with a digit: 123
      Hello world, this is plain printf.
      "


      This workaround is of course incomplete: if you call puts directly, or link in object files that call printf("simple string") and were not compiled with -fno-builtin-printf (perhaps from 3rd-party library), then you'll still have a problem.



      Unfortunately you can't assign to _IO_stdout (which is a macro). The only other thing you could do (that I can think of) is link in your own puts, which just returns printf("%s", arg). That should work if you are linking against libc.so.6, but may cause trouble if you link against libc.a.






      share|improve this answer




























        5












        5








        5







        This appears to be a bug in GLIBC.



        The reason that printf("simple string") works differently from printf("foo %d", 123) is that GCC transforms the former into a puts, with the notion that they are equivalent.



        As far as I can tell, they should be equivalent. This man page states that puts outputs to stdout, just like printf does.



        However, in GLIBC printf outputs to stdout here, but puts outputs to _IO_stdout here, and these are not equivalent. This has already been reported as a glibc bug (upstream bug).



        To work around this bug, you could build with -fno-builtin-printf flag. That prevents GCC from transforming printf into puts, and on my system produces:



        $ ./a.out
        my_write_func received 126 bytes
        Text is: "This is a long string, fprintf'd to stdout
        Hello world, this is a printf with a digit: 123
        Hello world, this is plain printf.
        "


        This workaround is of course incomplete: if you call puts directly, or link in object files that call printf("simple string") and were not compiled with -fno-builtin-printf (perhaps from 3rd-party library), then you'll still have a problem.



        Unfortunately you can't assign to _IO_stdout (which is a macro). The only other thing you could do (that I can think of) is link in your own puts, which just returns printf("%s", arg). That should work if you are linking against libc.so.6, but may cause trouble if you link against libc.a.






        share|improve this answer















        This appears to be a bug in GLIBC.



        The reason that printf("simple string") works differently from printf("foo %d", 123) is that GCC transforms the former into a puts, with the notion that they are equivalent.



        As far as I can tell, they should be equivalent. This man page states that puts outputs to stdout, just like printf does.



        However, in GLIBC printf outputs to stdout here, but puts outputs to _IO_stdout here, and these are not equivalent. This has already been reported as a glibc bug (upstream bug).



        To work around this bug, you could build with -fno-builtin-printf flag. That prevents GCC from transforming printf into puts, and on my system produces:



        $ ./a.out
        my_write_func received 126 bytes
        Text is: "This is a long string, fprintf'd to stdout
        Hello world, this is a printf with a digit: 123
        Hello world, this is plain printf.
        "


        This workaround is of course incomplete: if you call puts directly, or link in object files that call printf("simple string") and were not compiled with -fno-builtin-printf (perhaps from 3rd-party library), then you'll still have a problem.



        Unfortunately you can't assign to _IO_stdout (which is a macro). The only other thing you could do (that I can think of) is link in your own puts, which just returns printf("%s", arg). That should work if you are linking against libc.so.6, but may cause trouble if you link against libc.a.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 1 at 8:24









        Florian Weimer

        16.9k31148




        16.9k31148










        answered Dec 30 '18 at 21:41









        Employed RussianEmployed Russian

        126k20169239




        126k20169239
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53980112%2fredirect-printf-to-fopencookie%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            android studio warns about leanback feature tag usage required on manifest while using Unity exported app?

            SQL update select statement

            'app-layout' is not a known element: how to share Component with different Modules