on the way to C++ (unix-)daemons … : FILE* to iostream

Writing a unix daemon using C++, the idea might seem odd. But it’s desirable in many ways :

  • C++ provides a lot of methods which are inherently safe and neat regarding string treatments,
  • STL(sgi) provides a lot of nice containers, particularly the associative map,
  • convenient simple text input/output using iostream …

Now, coding a daemon implies a lot of very unix-native C details such as : properly detach from terminals, output some errors via syslog …

When one realises all those functionnalites have simple posix-C functions to take care of, a very convenient bridge from C to C++ is to bind a regular iostream to a FILE* descriptor.

Example : reading from a pipe using istream
The below posix-C function :

FILE *popen(const char *command, const char *type);

provides a very simple way to fork and read to (or write from) another process. The gnu iostream library documentation mentions some methods usable to turn FILE* into stream, but I would not say the said documentation made it straighforward. So here’s an example of such a pipe :

#include <errno.h>
#include <string.h>     // strerror

#include <iostream>
#include <ext/stdio_filebuf.h>  // __gnu_cxx::stdio_filebuf

using namespace std;

void filter_uggly_uppercase (istream &in, ostream &out) {
    char c;
    while (in && in.get(c)) {
        if ((c>='a') && (c<='z'))
            out << (char)('A' - 'a' + c);
        else
            out << c;
    }
}

int main (void) {
    const char *command = "find . -type f";

    FILE *f_pipe_in = popen (command, "r");
    if (f_pipe_in == NULL) {
        int e = errno;
        cerr << "error at piping from " << command << " : " << strerror (e) << endl;
        return 1;
    }

    // let's build a buffer from the FILE* descriptor ...
    __gnu_cxx::stdio_filebuf<char> pipe_buf (f_pipe_in, ios_base::in);

    // there we are, a regular istream is build upon the buffer :
    istream stream_pipe_in (&pipe_buf);

    // let's read from that pipe now, the usual way ...
    filter_uggly_uppercase (stream_pipe_in, cout);

    pclose (f_pipe_in);

    return 0;
}

on the way to C++ (unix-)daemons … : FILE* to iostream