Could people with compiler != g++ 2.95 please try the attached
version?

Andre'

-- 
André Pönitz .............................................. [EMAIL PROTECTED]
/* 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(const char * cmd);

private:
        /// unimplemented
        pipestream(pipestream const &);
        /// unimplemented
        void operator=(pipestream const &);
};

#endif
// pipestream.C -*- 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


// You can simultaneously read and write into a pipebuf just like you
// can listen and talk through a telephone. Hence, the read and the write
// buffers are different. That is, they do not share the same memory.
//
// Read: gptr() points to the start of the get area.  The unread chars are
// gptr() - egptr().  base() points to the read buffer
//
// eback() is set to base() so that pbackfail() is called only when there
// is no place to putback a char. And pbackfail() always returns EOF.
//
// Write: pptr() points to the start of the put area The unflushed chars
// are pbase() - pptr() pbase() points to the write buffer.  epptr()
// points to the end of the write buffer.
//
// Output is flushed whenever one of the following conditions holds: (1)
// pptr() == epptr() (2) EOF is written (3) linebuffered and '\n' is
// written
//
// Unbuffered: Input buffer size is assumed to be of size 1 and output
// buffer is of size 0. That is, egptr() <= base()+1 and epptr() ==
// pbase().

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

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

#include "pipestream.h"

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

namespace {

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

}



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);
        /// no copying to save us ref counting sockets
        pipebuf(const pipebuf &);
        /// no assignment
        pipebuf & operator=(const pipebuf &);
        /// destructor
        ~pipebuf();
        ///
        streamsize xsputn(char_type const * s, streamsize n);

private:
        /// try to reduce the number of #ifdef in "client code"
        static int_type end_of_file();
        ///
        int_type overflow(int_type c = end_of_file());
        ///
        int_type underflow();
        ///
        bool flush();
        ///

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



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
}


// 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 false;

        streamsize len  = pptr() - pbase();
        streamsize rlen = len;
        streamsize wlen = 0;
        while (rlen > 0) {
                streamsize wval = ::write(sock_, pbase(), rlen);
                if (wval == -1) {
                        error("pipebuf::write");
                        break;
                }
                rlen -= wval;
                wlen += wval;
        }
        setp(pbase(), pbase() + bufsize_);
        return len == wlen;
}


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

        int_type rval = ::read(sock_, gbuf_, bufsize_);
        if (rval == -1)
                error("pipebuf::read");
        if (rval == 0)
                return end_of_file();

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


// if c == EOF, return flush();
// if c == '\n' and linebuffered, insert c and
// return (flush() == EOF) ? EOF : c;
// otherwise insert c into the buffer and return c
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(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 (*p == '\n') {
                        if (overflow(*p) == end_of_file())
                                return i;
                } else
                        if (sputc(*p) == end_of_file())
                                return i;
        }
        return n;
}



/////////////////////////////////////////////////////////////////

extern char** environ;

namespace {

pipebuf * create(const char * 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("pipestream: socketpair");
                return 0;
        }

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

        if (pid == 0) {
                // child process
                if (::close(sockets[1]) == -1)
                        error("pipestream: child close 1");
                if (::dup2(sockets[0], 1) == -1) {
                        error("pipestream: child dup2 1");
                        _exit(0x70);
                }
                if (::dup2(sockets[0], 0) == -1) {
                        error("pipestream: child dup2 0");
                        _exit(0x71);
                }
                if (::close(sockets[0]) == -1)
                        error("pipestream: child close 0");
                const char * argv[4];
                argv[0] = "/bin/sh";
                argv[1] = "-c";
                argv[2] = cmd;
                argv[3] = 0;
                execve("/bin/sh", const_cast<char**>(argv), environ);
                error("pipestream: execve");
                _exit(0x7f);
        }
        // parent process
        pipebuf * s = new pipebuf(sockets[1]);
        if (::close(sockets[0]) == -1)
                error("pipestream: parent close 0");
        return s;
}

} // end anon namespace


pipestream::pipestream(const char * cmd)
        : ios(create(cmd))
{}



#ifdef PIPESTREAM_MAIN

#include <string>

int main()
{
        if (1) {
                pipestream ps("maple -q");
                ps << "2^64;\n";
                std::string result;
                ps >> result;
                std::cout << "res: " << result << "\n";
        }

        if (0) {
                pipestream ps("ls -la");
                while (ps) {
                        std::string line;
                        getline(ps, line);
                        std::cout << "res: " << line << "\n";
                }
        }

        return 0;
}
        

#endif // PIPESTREAM_MAIN

Reply via email to