1

I'm using the non-standard function warn() (provided by BSD) to output an error message if a file can't be opened, like so:

std::string path = get_path() ;
std::ifstream file(path) ;
if (file.is_open()) { /* do something */ }
else {
    warn("%s", path.c_str()) ;
    // uses errno to figure out what the error was and outputs it nicely along with the filename
}

That's all very well for outputting it, but what if I want to use the entire string somewhere else, in addition to printing it? The warn() functions don't seem to have a form that writes the error to a string. I've tried rolling my own, but it seems awfully cumbersome in comparison (besides not getting the program's name):

this->foo((boost::format("%s: %s") % path % strerror(errno)).str()) ;

So how do I get warn()'s output as a string?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Blacklight Shining
  • 1,468
  • 2
  • 11
  • 28

3 Answers3

1

warn puts its output on the standard error output. So you would have to create a mechanism to redirect standard error output to a location that you can read back into a string. The most straight forward way may be to redirect standard error to a file, and then read the file back as a string. You could, for instance, try to use dup2() to accomplish this (as explained in the answer to this question).

However, wrapping your own version of warn is probably a better choice. You may consider the C vsnprintf() function to implement it, though. There are answers to this question that address both using boost::format and vsnprintf().

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
0

You're right — there's no sprintf analog (i.e. that is, no hypothetical swarn function).

Your approach seems viable.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

It would appear that your gyrations produce a result similar to:

path + ": " +  strerror(errno);

At a guess, the "program's name" that it's including is probably just argv[0], so you could apparently produce a roughly equivalent of your warn that just returns a std::string with something on this general order:

std::string warn_s(std::string const &path) { 
    char *pname = strrchr(argv[0], '/');
    if (pname == NULL)
        pname = argv[0];
    return path + pname + ":  " + strerror(errno);
}

The major difficulty here is that argv is local to main, so you'll probably need to either save it into an accessible location in main, or else use some non-standard mechanism to re-retrieve that data in your function.

Unfortunately, the documentation for warn I was able to find was poor enough that a bit of testing/trial and error will probably be needed if you want to duplicate its output precisely.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111