Software Design

Design de software em C, C++, Java, etc…

C++ Class to encapsulate posix popen

Recently I needed to call a linux command from my application, the problem was that the command doesn’t takes all the input by parameters, and my application needed to send data to it’s input stream.

The posix popen is like system, but it returns a file descriptor that may be used for reading from or writting to the called process.

Because I don’t want to be spreading calls to system’s functions all over the application’s sources, I figured that I could encapsulate all I need in a single and simple class, that I called OutputPipe.

Basically this class encapsulate the calls to popen, pclose and write. It also holds the FILE* pointer, in order to do all the stream handling.

File: OutputPipe.h

#include <stdio.h>

#include <string>

#ifndef _OUTPUTPIPE_H_
#define _OUTPUTPIPE_H_

namespace util {

  /**
   * Encapsulates the POSIX popen command in order to become an easy way of
   * running commands and sending data to the command stdin. The usage of this
   * class must be:
   *
   * {
   *  OutputPipe opipe(command);
   *  opipe << "write to the command
   * }
   *
   * the class automatically closes the pipe file descriptor in the destructor,
   * but this can also be done by calling the close() method
   */
  class OutputPipe {
    public:
      /**
       * @brief This constructor already opens the pipe bypassing the command
       * parameter to the popen function. You must check if good() returns true
       * before starting to write in the pipe's output
       *
       * @param command: the command to be passed to popen function
       * */
      OutputPipe(const std::string &command);

      /**
       * @brief Default constructor: do nothing. After constructing the class
       * this way you must call the open method to start writing in the pipe
       * */
      OutputPipe();

      /**
       * @brief the destructor calls close
       * */
      ~OutputPipe();

      /**
       * @return returns true if the fd is opened and may be written
       * */
      bool good() { return fd != NULL; };

      /**
       * @brief calls popen and gets the file descriptor
       *
       * @param command: the command that will be passed to popen
       * @return true if the pipe was opened correctly
       * */
      bool open(const std::string &command);

      /**
       * @brief closes the pipe's file descriptor
       * */
      void close();

      /**
       * @brief operator<< outputs data to the pipe's file descriptor
       *
       * @return a reference to the OutputPipe object itself
       * */
      OutputPipe& operator<<(const std::string &v);

    private:
      FILE* fd;
  };
}
#endif  // _OUTPUTPIPE_H_

And OutputPipe.cpp

#include "OutputPipe.h"

#include <stdio.h>

#include <string>
#include <fstream>
#include <iostream>

using std::string;
using std::vector;
using std::map;

namespace util {

	OutputPipe::OutputPipe() : fd(NULL) {
	}

	OutputPipe::OutputPipe(const std::string& command) : fd(NULL) {
		open(command);
	}

	OutputPipe::~OutputPipe() {
		close();
	}

	bool OutputPipe::open(const std::string& command) {
		if ( command.length() == 0 ) return false;
		fd = popen(command.c_str(), "w");
		return (fd != NULL);
	}

	void OutputPipe::close() {
		if ( fd != NULL ) {
			pclose(fd);
			fd = NULL;
		}
	}

	OutputPipe& OutputPipe::operator<<(const std::string& v) {
		if ( !good() ) return *this;
		fputs(v.c_str(), fd);
		fflush(fd);
		return *this;
	}

}

USAGE:
Using this class is very easy. The only thing you need is to instantiate it and send data to it’s stream through the << operator. Example:

void someMethod() {
  OutputPipe pipe ("cat >> /tmp/test.txt");
  pipe << "This is a test... \r\n";
  pipe << "Another line";
}

There’s no need to call pipe.close() because the OutputPipe desctructor does this for us.
TODOs

The class can be improved by adding operator<< for other data types ( int, bool, etc ). An ostringstream object may be encapsulated in order to do the conversions and sending the data to the FILE*

REFERENCES

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às junho 22, 2011 por em C++, FreeBSD, Linux, MacOSX, Unix e marcado , , , , , .

Navegação

%d blogueiros gostam disto: