Now, I’m sure you’ve already heard that, in C and C++, you should never, ever, ever, use system(). And that’s correct. It’s very tempting to concat a few strings and assemble a command line to pass to system().

But that is a time bomb. One day you’ll have a part of that string that has a space, or a quote, and in the best case, everything will just break; in the worst case, you’ll be calling the mom of Bobby Tables.

But, the secure alternative is soooo much work. You have to fork, and exec, and compose an array of char* with a nullptr sentinel, and wait, and use macros like WIFEXITED and WEXITSTATUS. And don’t even mention capturing or redirecting the output. You’ll pipe, dup and select the sanity out of your mind.

I’ve used QProcess in the past, but lately, I’ve been doing small utilities for which it makes no sense to depend on Qt. I’d love it if there was something in the standard library or in boost, but I found nothing.

So I wrote this simple, still incomplete, C++ class called command that you can use like this:

command cmd;
cmd << "convert" << inputimage << "output.jpg";
cmd.run()

In the code above, inputimage is a string, and you don’t have to worry about any escaping issues.

Here are a few more things you can do:

command cmd;

// you can pass strings, int, doubles
// and boost::filesystem::paths if you
// have it
int page = 1;
double dpi = 150;
boost::filesystem::path inputpdf { argv[0] };
cmd << "pdftocairo"
    << "-f" << page
    << "-r" << dpi
    <<  inputpdf;
int exitstatus = cmd.run();

// silence stdout, stderr or both in one go
cmd.silence_stdout();
cmd.silence_stderr();       
cmd.silence();                      

// capture stdout using a ostream
cmd.stdout(some_output_stream);

// stderr can go to its own stream
// or share stdout's
cmd.stderr(some_output_stream);

// run the command in background
cmd.run_async();

// ask if it's still running
cmd.is_running();

// and wait later for it to finish and
// get its exit status
int exitstatus = cmd.wait();

// you can clear an instance to run a new command
cmd.clear();

The class is far from complete. It has only what I’ve needed it to have so far. For instance, I haven’t needed to feed anything to STDIN yet, so I haven’t implemented a stdin(istream&) method. Also, right now it only works on Linux. I haven’t ported it to any other platform.

If and when someone complains, I’ll ask them for pull-requests. The code is in GitHub.