On Mon, Aug 19, 2002 at 10:12:34AM +0100, Angus Leeming wrote:
> Didn't André post a pipestream class to the list some time ago? These sort of 
> semantic differences should be encapsulated and hidden away.

I believe there was a strong connection between "my" pipestream class
and socket++ (i.e. the pipestream is a cut-down version of the original
socket++ with a few tweaks)

The problem was that there were doubts on the license of the original code.
I try to contact the author but got no response. The original license said:

// Copyright (C) 1992,1993,1994 Gnanasekaran Swaminathan
//
// Permission is granted to use at your own risk and distribute this
// software in source and binary forms provided the above copyright
// notice and this paragraph are preserved on all copies.  This software
// is provided "as is" with no express or implied warranty.
//
// Version: 17Oct95 1.10

I think this puts us on the safe side, but there was no consensus AFAIR.

Andre'

PS: I'll attach the stuff in case anybody wants to have a look.

-- 
Those who desire to give up Freedom in order to gain Security,
will not have, nor do they deserve, either one. (T. Jefferson)
/* This file is part of
 * ======================================================
 *
 *           LyX, The Document Processor
 *
 *           Copyright 2001 The LyX Team.
 *
 * ====================================================== */


#ifndef PIPESTREAM_H
#define PIPESTREAM_H

#include <iostream>

class pipestream : public std::iostream {
public:
        /// constructor taking the external command as argument
        explicit pipestream(char const * const cmd[]);
private:
        /// unimplemented
        pipestream(pipestream const &);
        /// unimplemented
        void operator=(pipestream const &);
};

#endif
// pipestream.h -*- C++ -*- socket library
// Copyright (C) 1992,1993,1994 Gnanasekaran Swaminathan <[EMAIL PROTECTED]>
// 
// Permission is granted to use at your own risk and distribute this software
// in source and binary forms provided the above copyright
// notice and this paragraph are preserved on all copies.
// This software is provided "as is" with no express or implied warranty.
//
// Version: 17Oct95 1.10

// [EMAIL PROTECTED]


#include "pipestream.h"


#ifdef WINDOWS

#include "klog.h"

pipestream::pipestream(char const * const[])
{
        kmissing();
}

#else

#include <sys/types.h>
#include <sys/socket.h>

#include <cstddef>
#include <cstdio>
#include <unistd.h>
#include <errno.h>

using std::streambuf;
using std::streamsize;


class pipebuf : public streambuf {

public:
#ifndef MODERN_STL_STREAMS
        typedef char char_type;
        typedef int  int_type;
#endif

public:
        /// The only constructor we need
        explicit pipebuf(int sock);
        /// destructor
        ~pipebuf();

private:
        /// no copying to save us ref counting sockets
        pipebuf(const pipebuf &);
        /// no assignment
        pipebuf & operator=(const pipebuf &);

        /// try to reduce the number of #ifdef in "client code"
        static int_type end_of_file();
        ///
        static char_type to_char_type(int_type c);
        ///
        int_type overflow(int_type c = end_of_file());
        ///
        int_type underflow();
        ///
        streamsize xsputn(char_type const * s, streamsize n);

        ///
        bool flush();

        ///
        static int const bufsize_ = 1024;
        /// get area
        char_type gbuf_[bufsize_];
        /// put area
        char_type pbuf_[bufsize_];
        /// our socket.
        int const sock_;
};


namespace {

void error(const char * msg, int exitcode = 0)
{
        if (errno)
                perror(msg);
        std::cerr << msg << std::endl;
        errno = 0;
        if (exitcode)
                _exit(exitcode);
}


pipebuf * pipebuf_create(char const * const cmd[])
{
        // child closes sockets[1] and uses sockets[0]
        // parent closes sockets[0] and uses sockets[1]
        int sockets[2];
        if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
                error("socketpair");
                return 0;
        }

        pid_t pid = vfork();
        //pid_t pid = fork();
        if (pid == -1) {
                error("fork");
                return 0;
        }

        if (pid == 0) {
                // this is the child
                if (::close(sockets[1]) == -1)
                        error("child close 1");
                if (::dup2(sockets[0], 1) == -1)
                        error("child dup2 1", 10);
                if (::dup2(sockets[0], 0) == -1)
                        error("child dup2 0", 11);
                if (::close(sockets[0]) == -1)
                        error("child close 0");
                execvp(cmd[0], const_cast<char**>(cmd));
                error("execve", 12);
        }
        // this is the parent
        pipebuf * s = new pipebuf(sockets[1]);
        if (::close(sockets[0]) == -1)
                error("parent close 0");
        return s;
}

} // end anon namespace




pipebuf::pipebuf(int sock)
        : sock_(sock)
{
        setg(gbuf_, gbuf_, gbuf_);
        setp(pbuf_, pbuf_ + bufsize_);
}


pipebuf::~pipebuf()
{
        overflow();
        ::close(sock_);
}


pipebuf::int_type pipebuf::end_of_file()
{
#ifdef MODERN_STL_STREAMS
        return traits_type::eof();
#else
        return EOF;
#endif
}


pipebuf::char_type pipebuf::to_char_type(int_type c)
{
#ifdef MODERN_STL_STREAMS
        return traits_type::to_char_type(c);
#else
        return static_cast<char_type>(c);
#endif
}


// return true when there is nothing to flush or when the flush is a success
// return false when it could not flush
bool pipebuf::flush()
{
        if (pptr() == pbase())
                return true;

        streamsize n;
        for (streamsize len = pptr() - pbase(); len > 0; len -= n) {
                n = ::write(sock_, pbase(), len);
                if (n == -1) {
                        error("write");
                        setp(pbase(), pbase() + bufsize_);
                        return false;
                }
        }

        setp(pbase(), pbase() + bufsize_);
        return true;
}


pipebuf::int_type pipebuf::underflow()
{
        if (gptr() < egptr())
                return gptr() != 0;

        streamsize n = ::read(sock_, gbuf_, bufsize_);
        if (n == 0)
                return end_of_file();
        if (n == -1)
                error("read");

        setg(eback(), gbuf_, gbuf_ + n);
        return gptr() != 0;
}


pipebuf::int_type pipebuf::overflow(int_type c)
{
        if (c == end_of_file())
                return flush() ? 0 : c;
        if (pptr() >= epptr())
                if (!flush())
                        return end_of_file();

        sputc(to_char_type(c));

        if (c == '\n' || pptr() >= epptr())
                if (!flush())
                        return end_of_file();
        return c;
}


streamsize pipebuf::xsputn(char_type const * p, streamsize n)
{
        if (n <= 0)
                return 0;
        for (streamsize i = 0; i < n; i++, p++)
                if (end_of_file() == ((*p == '\n') ? overflow(*p) : sputc(*p)))
                        return i;
        return n;
}



pipestream::pipestream(char const * const cmd[])
        : std::iostream(pipebuf_create(cmd))
{}

#endif



#ifdef PIPESTREAM_MAIN

#include <string>

int main()
{
        if (1) {
                char const * cmd[] = {"maple", "-q", 0};
                pipestream ps(cmd);
                ps << "2^64;\n";
                std::string result;
                ps >> result;
                std::cout << "res: " << result << "\n";
        }

        if (1) {
                char const * cmd[] = {"ls", "-la", 0};
                pipestream ps(cmd);
                while (ps) {
                        std::string line;
                        getline(ps, line);
                        std::cout << "res: " << line << "\n";
                }
        }

        return 0;
}
        

#endif // PIPESTREAM_MAIN

Reply via email to