FILE * and istream: connect the two?

后端 未结 3 1987
误落风尘
误落风尘 2020-12-10 15:37

Suppose I \"popen\" an executable, I get a FILE* in return. Furthermore, suppose I\'d like to \"connect\" this file to an istream object for easier

3条回答
  •  温柔的废话
    2020-12-10 16:40

    You can get away by deriving std::basic_streambuf or std::streambuf classes.
    Something along these lines:

    #include 
    #include 
    
    #define BUFFER_SIZE     1024
    
    class popen_streambuf : public std::streambuf {
    public:
        popen_streambuf() : fp(NULL) {
        }
        ~popen_streambuf() {
            close();
        }
        popen_streambuf *open(const char *command, const char *mode) {
            fp = popen(command, mode);
            if (fp == NULL)
                return NULL;
            buffer = new char_type[BUFFER_SIZE];
            // It's good to check because exceptions can be disabled
            if (buffer == NULL) {
                close();
                return NULL;
            }
            setg(buffer, buffer, buffer);
            return this;
        }
        void close() {
            if (fp != NULL) {
                pclose(fp);
                fp = NULL;
            }
        }
        std::streamsize xsgetn(char_type *ptr, std::streamsize n) {
            std::streamsize got = showmanyc();
            if (n <= got) {
                memcpy(ptr, gptr(), n * sizeof(char_type));
                gbump(n);
                return n;
            }
            memcpy(ptr, gptr(), got * sizeof(char_type));
            gbump(got);
    
            if (traits_type::eof() == underflow()) {
                return got;
            }
            return (got + xsgetn(ptr + got, n - got));
        }
        int_type underflow() {
            if (gptr() == 0) {
                return traits_type::eof();
            }
            if (gptr() < egptr()) {
                return traits_type::to_int_type(*gptr());
            }
            size_t len = fread(eback(), sizeof(char_type), BUFFER_SIZE, fp);
            setg(eback(), eback(), eback() + (sizeof(char_type) * len));
            if (0 == len) {
                return traits_type::eof();
            }
            return traits_type::to_int_type(*gptr());
        }
        std::streamsize showmanyc() {
            if (gptr() == 0) {
               return 0;
            }
            if (gptr() < egptr()) {
                return egptr() - gptr();
            }
            return 0; 
        }
    private:
        FILE *fp;
        char_type *buffer;
    };
    
    int main(int argc, char *argv)
    {
        char c;
        popen_streambuf sb;
        std::istream is(&sb);
    
        if (NULL == sb.open("ls -la", "r")) {
            return 1;
        }
    
        while (is.read(&c, 1)) {
            std::cout << c;
        }
    
        return 0;
    }
    

提交回复
热议问题