text: // $Id: mfstream.h 383 2010-04-23 15:29:28Z nicolabertoldi $
  
  /******************************************************************************
  IrstLM: IRST Language Model Toolkit, compile LM
  Copyright (C) 2006 Marcello Federico, ITC-irst Trento, Italy
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
  
  ******************************************************************************/
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <string.h>
  #include <iostream>
  #include <cstring>
  #include <cstdlib>
  #include <fstream>
  #include <streambuf>
  #include <cstdio>
  
  using namespace std;
  
  #ifndef MF_STREAM_H
  #define MF_STREAM_H
  
  extern "C" {
    ssize_t write (int fd, const void* buf, size_t num);
    ssize_t read (int fd,  void* buf, size_t num);
    FILE *popen(const char *command, const char *type);
    int pclose(FILE *stream);
    int fseek( FILE *stream, long offset, int whence);
    long ftell( FILE *stream);
  };
  
  
  //! File description for I/O stream buffer
  class fdbuf : public std::streambuf {
  
  protected:
    int fd;    // file descriptor
  
    // write one character
    virtual int_type overflow (int_type c) {
      char z = c;
        if (c != EOF) {
  	if (write (fd, &z, 1) != 1) {
  	  return EOF;
  	}
        }
        //cerr << "overflow: \n";
        //cerr << "pptr: " << (int) pptr() << "\n";
        return c;
    }
  
    // write multiple characters
    virtual
    std::streamsize xsputn (const char* s,
  			  std::streamsize num) {
      return write(fd,s,num);
  
    }
  
    virtual streampos seekpos ( streampos /* unused parameter: sp */, ios_base::openmode /* unused parameter: which */= ios_base::in | ios_base::out ){
      std::cerr << "mfstream::seekpos is not implemented" << std::endl;;
  
      return (streampos) 0;
    }
  
    //read one character
    virtual int_type underflow () {
      // is read position before end of buffer?
          if (gptr() < egptr()) {
              return traits_type::to_int_type(*gptr());
          }
  
          /* process size of putback area
           * - use number of characters read
           * - but at most four
           */
          int numPutback;
          numPutback = gptr() - eback();
          if (numPutback > 4) {
              numPutback = 4;
          }
  
          /* copy up to four characters previously read into
           * the putback buffer (area of first four characters)
           */
          std::memmove (buffer+(4-numPutback), gptr()-numPutback,
                        numPutback);
  
          // read new characters
          int num;
          num = read (fd, buffer+4, bufferSize-4);
          if (num <= 0) {
              // ERROR or EOF
              return EOF;
          }
  
          // reset buffer pointers
          setg (buffer+(4-numPutback),   // beginning of putback area
                buffer+4,                // read position
                buffer+4+num);           // end of buffer
  
          // return next character
          return traits_type::to_int_type(*gptr());
    }
  
  
    // read multiple characters
    virtual
    std::streamsize xsgetn (char* s,
  			  std::streamsize num) {
      return read(fd,s,num);
    }
  
    static const int bufferSize = 10;    // size of the data buffer
    char buffer[bufferSize];             // data buffer
  
  public:
  
    // constructor
    fdbuf (int _fd) : fd(_fd) {
      setg (buffer+4,     // beginning of putback area
  	  buffer+4,     // read position
  	  buffer+4);    // end position
    }
  
  };
  
  
  
  //! Extension of fstream to commands
  
  class mfstream : public std::fstream{
  
  protected:
    fdbuf* buf;
    int _cmd;
    openmode _mode;
    FILE* _FILE;
    
  
    int swapbytes(char *p, int sz, int n);
  
  public:
  
    char _cmdname[500];
  
    //! Creates and opens a  file/command stream in a specified nmode
    mfstream (const char* name,openmode mode) : std::fstream() {
      _cmdname[0]='\0';
      _mode=mode;
      open(name,mode);
    }
    
    //! Closes and destroys a file/command stream
    ~mfstream(){
      if (_cmd<2) close();
    }
  
    //! Opens an existing mfstream 
    void open(const char *name,openmode mode);
  
    //! Closes an existing mfstream 
    void close();
  
    //! Write function for machine-independent byte order
    mfstream& writex(void *p, int sz,int n=1);
  
    //! Read function for machine-independent byte order
    mfstream& readx(void *p, int sz,int n=1);
    
    //! Write function at a given stream position for machine-independent byte order
    mfstream& iwritex(streampos loc,void *ptr,int size,int n=1);
    
    //! Tells current position within a file
    streampos tellp(){
      if (_cmd==0) return (streampos) fstream::tellg();
      cerr << "tellp not allowed on commands\n";
      exit(1);
    }
  
    //! Seeks a position within a file
    mfstream& seekp(streampos loc){
      if (_cmd==0) 
        fstream::seekg(loc);
      else{
        cerr << "seekp not allowed on commands\n";
        exit(1);
      }
      return *this;
    }
  
    //! Reopens an input stream
  
    mfstream& reopen(){
  
      if (_mode != in){
        cerr << "mfstream::reopen() openmode must be ios:in\n";
        exit(1);
      }
  
      if (strlen(_cmdname)>0){
        char *a=new char[strlen(_cmdname)+1];
        strcpy(a,_cmdname);
        cerr << "close/open " << a <<"\n";
        close();
        open(a,ios::in);
      }
      else
        seekp(0);
  
      return *this;
    }
  
  };
  
  
  #endif
  