#ifndef _FSTREAM_H
#define _FSTREAM_H

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>

namespace std {

struct io_exception { };

class ios {
public:
    enum { 
       in = 1,  
       out = 2,
       app = 4,
       binary = 8,
       trunc = 16,
       ate = 32
    };
};

inline
void
truncate_file(const string & file_name)
{
   unlink(file_name.c_str());
   fclose(fopen(file_name.c_str(), "w"));
}

class ifstream : public istream {
   //FILE * in;
   bool do_close;

public:
   ifstream(const char * file_name, int mode) {
      if(mode & ios::trunc) truncate_file(file_name);
      in = fopen(file_name, "r");
      do_close = true;
   }

   ifstream(const char * file_name) {
      in = fopen(file_name, "r");
      do_close = true;
   }

   ifstream() {
      in = 0;
      do_close = false;
   }

   bool open(const char * file_name, int mode) {
      if(mode & ios::trunc) truncate_file(file_name);
      in = fopen(file_name, "r");
      do_close = true;
   }
   
   virtual ~ifstream() {
      if(do_close)
         if(in) 
            fclose(in);
   }

   void close() {
      if(do_close) {
         if(in)
            fclose(in);
         do_close = false;
      }
   } 

   operator void*() {
      if(in == NULL) return NULL;
      return (void*)(feof(in) == 0);
   }

   void clear() {
      clearerr(in);
   }

   char get() {
      return fgetc(in);
   }

   char peek() {
      char ch = get();
      ungetc(ch, in);
      return ch;
   }

   void uget(char ch) {
      ungetc(ch, in);
   }

   ifstream & operator>>(char & ch) {
      ch = fgetc(in);
      return *this;
   }

   ifstream & operator>>(int & i) {
      fscanf(in, "%d", &i);
      return *this;
   }

   ifstream & operator>>(float & f) {
      fscanf(in, "%f", &f);
      return *this;
   }

   ifstream & operator>>(double & d) {
      fscanf(in, "%d", &d);
      return *this;
   }

   ifstream & operator>>(long & l) {
      fscanf(in, "%l", &l);
      return *this;
   }

   ifstream & operator>>(unsigned int & i) {
      fscanf(in, "%u", &i);
      return *this;
   }

   ifstream & operator>>(unsigned long & l) {
      fscanf(in, "%ul", &l);
      return *this;
   }

   ifstream & operator>>(unsigned short & s) {
      int t;
      fscanf(in, "%ud", &t);
      s = t;
      return *this;
   }

   ifstream & operator>>(unsigned char & c) {
      c = fgetc(in);
      return *this;
   }
};

class ofstream : public ostream {
   //FILE * out;
   bool do_close;

public:
   ofstream(const char *  file_name, int mode) {
      if(mode & ios::trunc || mode & ios::ate) truncate_file(file_name);
      out = fopen(file_name, "w");
      do_close = true;
   }

   ofstream(const char * file_name) {
      out = fopen(file_name, "w");
      do_close = true;
   }

   virtual ~ofstream() {
      if(do_close) {
         if(out) 
            fclose(out);
         do_close = false;
      }
   }

   ofstream() {
      out = 0;
      do_close = false;
   }

   bool open(const char * file_name, int mode) {
      if(mode & ios::trunc) truncate_file(file_name);
      out = fopen(file_name, "w");
      do_close = true;
   }


   void close() { 
      if(do_close) {
         if(out) 
            fclose(out);
         do_close = false;
      }
   }

   void flush() {
      if(out) 
         fflush(out);
   }

   operator void*() {
      if(out == NULL) return 0;
      return (void*)(feof(out) == 0);
   }

   void clear() {
      if(out)
         clearerr(out);
   }

   ofstream & operator<<(const unsigned int i) {
      fprintf(out, "%u", i);
      return *this;
   }

   ofstream & operator<<(const unsigned char c) {
      fprintf(out, "%c", c);
      return *this;
   }

   ofstream & operator<<(const unsigned short s) {
      fprintf(out, "%s", s);
      return *this;
   }

   ofstream & operator<<(const unsigned long l) {
      fprintf(out, "%ul", l);
      return *this;
   }

   ofstream & operator<<(const int i) {
      fprintf(out, "%d", i);
      return *this;
   }

   ofstream & operator<<(const char c) {
      fprintf(out, "%c", c);
      return *this;
   }

   ofstream & operator<<(const long & l) {
      fprintf(out, "%d", l);
      return *this;
   }

   ofstream & operator<<(const float f) {
      fprintf(out, "%f", f);
      return *this;
   }

   ofstream & operator<<(const double & d) {
      fprintf(out, "%f", d);
      return *this;
   }

   ofstream & operator<<(const string & str) {
      fprintf(out, "%s", str.c_str());
      return *this;
   }

   ofstream & operator<<(const char * str) {
      fprintf(out, "%s", str);
      return *this;
   }

   ofstream & operator<<(ofstream & (*pf)(ofstream &)) {
      return pf(*this);
   }
};

inline
ofstream & endl(ofstream & out) {
   out << "\n";
   out.flush();
   return out;
}

inline
ofstream & flush(ofstream & out) {
   out.flush();
   return out;
}


class fstream : public istream, ostream {
   FILE * stream;
   bool do_close;

public:
   fstream(const char * file_name, int mode) {
      if(mode & ios::trunc || mode & ios::ate) truncate_file(file_name);
      if(mode & ios::in) {
         stream = fopen(file_name, "r");
      }
      else if(mode & ios::app) {
         stream = fopen(file_name, "a");
      }
      else {
         stream = fopen(file_name, "rw");
      }
      if(stream == NULL) throw "bad file..";
      do_close = true;
   }

   fstream(const char * file_name) {
      stream = fopen(file_name, "rw");
      if(stream == NULL) throw "bad file..";
      do_close = true;
   }

   virtual ~fstream() {
      if(do_close) {
         fclose(stream);
         do_close = false;
      }
   }

   operator void*() {
      if(stream == NULL) return 0;
      return (void*)(feof(stream) == 0);
   }

   void clear() {
      clearerr(stream);
   }

   void close() {
      if(do_close) {
         fclose(stream);
         do_close = false;
      }
   }

   char get() {
      char ch = fgetc(stream);
      return ch;
   }

   void unget(char c) {
      ungetc(c, stream);
   }

   size_t read(char * buffer, size_t n) {
      size_t retval = 0U;
      size_t i;
      for(i = 0; i < n && feof(stream) == 0; i++) {
         buffer[i] = get(); 
      }
      buffer[i] = '\0';
      return retval;
   }

   fstream & operator<<(const int i) {
      fprintf(stream, "%d", i);
      return *this;
   }

   fstream & operator<<(const char c) {
      fprintf(stream, "%c", c);
      return *this;
   }

   fstream & operator<<(const char * str) {
      fprintf(stream, "%s", str);
      return *this;
   }

   fstream & operator<<(const long & l) {
      fprintf(stream, "%d", l);
      return *this;
   }

   fstream & operator<<(const string & str) {
      fprintf(stream, "%s", str.c_str());
      return *this;
   }

   fstream & operator>>(char & ch) {
      ch = fgetc(stream);
      return *this;
   }

   fstream & operator>>(int & i) {
      fscanf(stream, "%d", &i);
      return *this;
   }

   fstream & operator>>(float & f) {
      fscanf(stream, "%f", &f);
      return *this;
   }

   fstream & operator>>(double & d) {
      fscanf(stream, "%f", &d);
      return *this;
   }

   fstream & operator>>(long & l) {
      fscanf(stream, "%l", &l);
      return *this;
   }

   fstream & operator>>(unsigned int & i) {
      fscanf(stream, "%u", &i);
      return *this;
   }

   fstream & operator>>(unsigned long & l) {
      fscanf(stream, "%ul", &l);
      return *this;
   }

   fstream & operator>>(unsigned char & c) {
      c = fgetc(stream);
      return *this;
   }
   fstream & operator>>(unsigned short & s) {
      fscanf(stream, "%d", &s);
      return *this;
   }
   fstream & operator>>(string & str) {
      char buffer[1024];
      fscanf(stream, "%s", buffer);
      str = buffer;
      return *this;
   }

   fstream & operator<<(fstream & (*pf)(fstream &)) {
      return pf(*this);
   }

   void flush() {
      fflush(stream);
   }

   char peek() {
      char ch = get();
      unget(ch);
      return ch;
   }
};

inline
fstream & endl(fstream & out) {
   out << "\n";
   out.flush();
   return out;
}

inline
fstream & flush(fstream & out) {
   out.flush();
   return out;
}


}

#endif /* _FSTREAM_H */
