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
  • 369,052
  • 73
  • 620
  • 1,021
Blacklight Shining
  • 1,358
  • 2
  • 10
  • 27

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
  • 66,730
  • 7
  • 105
  • 179
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
  • 369,052
  • 73
  • 620
  • 1,021
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
  • 455,417
  • 76
  • 598
  • 1,067