OKlibrary  0.2.1.6
StreamHandling.hpp
Go to the documentation of this file.
00001 // Oliver Kullmann, 29.5.2002 (Swansea)
00002 /* Copyright 2002 - 2007 Oliver Kullmann
00003 This file is part of the OKlibrary. OKlibrary is free software; you can redistribute
00004 it and/or modify it under the terms of the GNU General Public License as published by
00005 the Free Software Foundation and included in this library; either version 3 of the
00006 License, or any later version. */
00007 
00008 #ifndef STREAMHANDLINGWAECHTER
00009 
00010 #define STREAMHANDLINGWAECHTER
00011 
00012 #include <istream>
00013 #include <limits>
00014 #include <string>
00015 #include <iterator>
00016 #include <fstream>
00017 #include <memory> // for auto_ptr
00018 #include <new> // for bad_alloc
00019 #include <ios> // for ios_base::failure
00020 #include <cstdio> // for tmpnam, remove
00021 #include <algorithm>
00022 #include <sstream>
00023 #include <iostream>
00024 #include <cstddef>
00025 #include <streambuf>
00026 #include <iomanip>
00027 
00028 #include <unistd.h> // for close, write
00029 #include <stdio.h> // for mktemp
00030 #include <fcntl.h> // for open, fcntl
00031 #include <sys/stat.h> // for mode macros
00032 #include <sys/types.h>
00033 
00034 #include <OKlib/General/ErrorHandling.hpp>
00035 
00036 namespace StreamHandling {
00037 
00038   struct Error : ErrorHandling::Error {
00039     Error(const std::string& what) : ErrorHandling::Error(what) {}
00040   };
00041 
00042 }
00043 
00044 // ---------------------------------------------------------------------------
00045 // Redirection
00046 // ---------------------------------------------------------------------------
00047 
00048 namespace StreamHandling {
00049 
00050   // noch nicht fertig:
00051 
00052   class RedirectingStd {
00053   public :
00054 
00055     RedirectingStd() :
00056       in_buf(0), out_buf(0), err_buf(0), activated(false) {}
00057 
00058     void set(std::istream& in, std::ostream& out, std::ostream& err) {
00059       if (not activated) {
00060   using namespace std;
00061   in_buf = cin.rdbuf(); out_buf = cout.rdbuf(); err_buf = cerr.rdbuf();
00062   in_state = cin.rdstate(); out_state = cin.rdstate(); err_state = cerr.rdstate();
00063   cin.rdbuf(in.rdbuf()); cout.rdbuf(out.rdbuf()); cerr.rdbuf(err.rdbuf());
00064   cin.exceptions(ios_base::goodbit); cout.exceptions(ios_base::goodbit); cerr.exceptions(ios_base::goodbit);
00065   cin.clear(in.rdstate()); cout.clear(out.rdstate()); cerr.clear(err.rdstate());
00066       }
00067     }
00068     void unset() {
00069       if (activated) {
00070   using namespace std;
00071   cin.rdbuf(in_buf); cout.rdbuf(out_buf); cerr.rdbuf(err_buf);
00072       }
00073     }
00074 
00075   private :
00076 
00077     std::streambuf* in_buf; std::streambuf* out_buf; std::streambuf* err_buf;
00078     std::ios_base::iostate in_state; std::ios_base::iostate out_state; std::ios_base::iostate err_state;
00079     bool activated;
00080 
00081   };
00082 
00083 }
00084 
00085 // ---------------------------------------------------------------------------
00086 // Advancing lines in streams
00087 // ---------------------------------------------------------------------------
00088 
00089 namespace StreamHandling {
00090 
00091   inline std::istream& line_advance(std::istream& s, unsigned long int a) throw(std::ios_base::failure) {
00092     // If on entry s is false, then nothing happens. Else the following happens:
00093     // After completion, s.eof() is true (and thus bool(s) is false) iff 
00094     // not a-many complete lines (that is, including "\n") could be read;
00095     // otherwise, the stream pointer points to the first character after the
00096     // last eof-character (this first character may in fact be end-of-file).
00097 
00098     for (unsigned long int i = 0; i < a and s; i++)
00099       s.ignore(std::numeric_limits<int>::max(), '\n');
00100     return s;
00101   }
00102 
00103 }
00104 
00105 // ---------------------------------------------------------------------------
00106 // A very simple container for files, supporting an input line iterator
00107 // ---------------------------------------------------------------------------
00108 
00109 namespace StreamHandling {
00110 
00111   namespace Error_FileLines {
00112 
00113     struct open_file : Error {
00114       open_file(const std::string& what) : Error(what) {}
00115     };
00116     struct read_file : Error {
00117       read_file(const std::string& what) : Error(what) {}
00118     };
00119   }
00120 
00121   // std::ios_base::failure is only thrown if activated by the user
00122 
00123   class FileLinesInputIterator;
00124 
00125   class FileLines {
00126 
00127   public :
00128 
00129     typedef FileLinesInputIterator iterator;
00130 
00131     explicit FileLines(const std::string&) throw();
00132     FileLines(const FileLines&) throw();
00133     FileLines& operator = (const FileLines&) throw();
00134     bool operator == (const FileLines&) const throw();
00135     bool operator != (const FileLines&) const throw();
00136 
00137     std::streamsize size() const throw(Error_FileLines::open_file, Error_FileLines::read_file, std::ios_base::failure);
00138     // requires linear complexity
00139     
00140     iterator begin() const throw(Error_FileLines::open_file, std::ios_base::failure, std::bad_alloc);
00141     iterator end() const throw();
00142 
00143     // the end-iterator is a generic one, and doesn't look at the file
00144 
00145   private :
00146 
00147     std::string filename;
00148   };
00149 
00150   // Additionally to the usual operations for input iterators we have the
00151   // operation +, which is "lazily" implemented, so that running through
00152   // the file only occurs when we have to:
00153   // 1. if we want to read a line;
00154   // 2. we compare it with an end-iterator.
00155   // Additionally to the usually guarantees for input iterators (which assume,
00156   // that dereferenciation happens only in the valid range, and that
00157   // pointer arithmetic never goes beyond the end), we have that
00158   // "iterator + n" is compared equal to an end-iterator if from the current
00159   // position of "iterator" there are less than n lines to the end
00160   // (when using "iterator + n" it is assumed, that iterator has not
00161   // become an end-iterator, which in case of using "+" becomes only
00162   // apparent when using "*", "==", "!=" or "++" thereafter).
00163   // Each assignment or copying for these iterators transfers ownership.
00164 
00165   // Examples:
00166 
00167   /*
00168     FileLines f(name);
00169     FileLines::iterator it = f.begin();
00170     it = it + 7;
00171     cout << (it == f.end()) << endl;
00172     cout << *it << endl;
00173     cout << (it == f.end()) << endl; // didn't change (of course)
00174     cout << *++it << endl;
00175     cout << *it << endl;
00176     copy(f.begin() + 2, f.begin() + 4, ostream_iterator<string>(cout));
00177     copy(f.begin() + 6, f.begin() + std::numeric_limits<unsigned long int>::max(), ostream_iterator<string>(cout)); // if the file is not too big, this will have the same effect as
00178     copy(f.begin() + 6, f.end(), ostream_iterator<string>(cout));
00179   */
00180 
00181   class FileLinesInputIterator : public std::iterator<std::input_iterator_tag, std::string, void, void, void> {
00182 
00183   public :
00184 
00185     FileLinesInputIterator(const FileLinesInputIterator&) throw();
00186     // attention: fake "const" (otherwise return in the above begin and end
00187     // does not compile)
00188     FileLinesInputIterator& operator = (FileLinesInputIterator&) throw();
00189 
00190     bool operator == (const FileLinesInputIterator&) const throw();
00191     bool operator != (const FileLinesInputIterator&) const throw();
00192 
00193     value_type operator *() const throw(Error_FileLines::read_file, std::ios_base::failure);
00194     // the line-end-symbol is not included in the string returned by *;
00195     // evaluation needs to go to the file (always in forward direction) from
00196     // the position of the last read to the current position --- this is not
00197     // done at the time when applying operator +, and not for the last line
00198     // when applying operator ++;
00199     FileLinesInputIterator& operator++() throw(Error_FileLines::read_file, std::ios_base::failure);
00200 
00201     FileLinesInputIterator& operator+(unsigned long int) throw();
00202     // does not read the file;
00203 
00204   private :
00205 
00206     friend class FileLines;
00207 
00208     FileLinesInputIterator() throw();
00209     FileLinesInputIterator(const std::string&) throw(Error_FileLines::open_file, std::ios_base::failure, std::bad_alloc);
00210 
00211     struct _impl {
00212       std::ifstream s;
00213       value_type line;
00214       std::streamsize current_line;
00215       // implicitely points to the beginning of the current line, while
00216       // last_line_read implicitely points to the end-of-line of that
00217       // last line;
00218       std::streamsize last_line_read;
00219       // invariant: current_line >= last_line_read
00220 
00221       _impl (const std::string&) throw(Error_FileLines::open_file, std::ios_base::failure);
00222     };
00223 
00224     mutable std::auto_ptr<_impl> p;
00225 
00226     void update() const throw(Error_FileLines::read_file, std::ios_base::failure);
00227 
00228   };
00229 
00230 }
00231 
00232 // -----------------------------
00233 // Temporary files
00234 // -----------------------------
00235 
00236 namespace StreamHandling {
00237 
00238   namespace Error_TempFile {
00239 
00240     struct open_file : Error {
00241       open_file(const std::string& what) : Error(what) {}
00242     };
00243     struct remove_file : Error {
00244       remove_file(const std::string& what) : Error(what) {}
00245     };
00246     struct call_mktemp : Error {
00247       call_mktemp(const std::string& what) : Error(what) {}
00248     };
00249     struct call_open : Error {
00250       call_open(const std::string& what) : Error(what) {}
00251     };
00252     struct call_close : Error {
00253       call_close(const std::string& what) : Error(what) {}
00254     };
00255   }
00256 
00257 
00258   // Policy classes for creating a temporary file and its name
00259   // ---------------------------------------------------------
00260 
00261   const char * const template_part = "XXXXXX";
00262   const int length_template_part = 6;
00263   
00264   class path_template {
00265   public :
00266     struct Parameter {
00267       Parameter(const std::string& directory, const std::string& basename) :
00268   dir(directory), base(basename) {}
00269       const std::string& dir, base;
00270     };
00271   protected :
00272     ~path_template() { delete[] buffer; }
00273     // throw()
00274 
00275     path_template(const Parameter& P) :
00276       length(P.dir.size() + 1 + P.base.size() + length_template_part + 1), buffer(new char[length])
00277     {
00278       char * pointer = std::copy(P.dir.begin(), P.dir.end(), buffer);
00279       *(pointer++) = '/';
00280       pointer = std::copy(P.base.begin(), P.base.end(), pointer);
00281       std::copy(template_part, template_part + length_template_part + 1, pointer);
00282       if (! mktemp(buffer))
00283   throw Error_TempFile::call_mktemp("StreamHandling::path_template::path_template(const Parameter& P) : Call to mktemp failed");
00284       const int file_descriptor = open(buffer, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
00285       if (file_descriptor == -1)
00286   throw Error_TempFile::call_open("StreamHandling::path_template::path_template(const Parameter& P) : Call to open failed");
00287       if (close(file_descriptor))
00288   throw Error_TempFile::call_close("StreamHandling::path_template::path_template(const Parameter& P) : Call to close failed");
00289      }
00290     // throw(Error_TempFile::call_mkstemp, Error_TempFile::call_open, Error_TempFile::call_close)
00291 
00292     std::string create_name() const {
00293       return std::string(buffer, buffer + (length - 1));
00294     }
00295     // throw(std::length_error )
00296 
00297   private :
00298     const std::size_t length;
00299     char * buffer;
00300 
00301     path_template(const path_template&);
00302     path_template& operator = (const path_template&);
00303   };
00304 
00305   class basename_template : protected path_template {
00306   public :
00307     struct Parameter {
00308       Parameter(const std::string& basename) :
00309   base(basename) {}
00310       const std::string& base;
00311     };
00312   protected :
00313     basename_template(const Parameter& P) :
00314       path_template(path_template::Parameter("/tmp", P.base)) {}
00315   };
00316 
00317 
00318   class self_named {
00319   public :
00320 
00321     struct Parameter {
00322       Parameter(const std::string& full_name) :
00323   name(full_name) {}
00324       const std::string& name;
00325     };
00326 
00327   protected :
00328 
00329     ~self_named() {}
00330     // throw()
00331 
00332     self_named(const Parameter& P) :
00333       name_(P.name) {
00334       const int file_descriptor = open(name_.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
00335       if (file_descriptor == -1)
00336   throw Error_TempFile::call_open("StreamHandling::self_named::self_named(const Parameter& P) : Call to open failed for " + name_);
00337       if (close(file_descriptor))
00338   throw Error_TempFile::call_close("StreamHandling::self_named::self_named(const Parameter& P) : Call to close failed for " + name_);
00339     }
00340     // throw(Error_TempFile::call_open, Error_TempFile::call_close)
00341 
00342     std::string create_name() const { return name_; }
00343 
00344   private :
00345     const std::string name_;
00346   };
00347 
00348 
00349   // Main class for creating temporary files
00350   // ----------------------------------------------------------
00351 
00352   template < class Creator >
00353   class TemporaryFile : public Creator {
00354   public :
00355 
00356     TemporaryFile(const typename Creator::Parameter& P) :
00357       Creator(P), name_(Creator::create_name()) {}
00358     // throw(Error_TempFile::open_file)
00359 
00360     void open() {
00361       file.open(name_.c_str(), std::ios::in | std::ios::out | std::ios::trunc);
00362       if (! file)
00363   throw Error_TempFile::open_file("StreamHandling::TemporaryFile::open() : Can not open file " + name_);
00364     }
00365     // throw(Error_TempFile::open_file, std::ios_base::failure)
00366     // opens for reading and writing with truncation
00367 
00368     std::fstream& f() { return file; }
00369     // throw()
00370 
00371     std::string name() const { return name_; };
00372     // throw()
00373 
00374     ~TemporaryFile() {
00375       if (file.is_open())
00376   file.close();
00377       if (std::remove(name_.c_str()))
00378   throw Error_TempFile::remove_file("StreamHandling::TemporaryFile::~TemporaryFile() : Can not remove file " + name_);
00379     }
00380     // throw(Error_TempFile::remove_file)
00381 
00382   private :
00383 
00384     const std::string name_; // full name of the temporary file
00385     std::fstream file;
00386 
00387     TemporaryFile(const TemporaryFile&);
00388     TemporaryFile& operator = (const TemporaryFile&);
00389   };
00390 
00391   template <class C, typename T>
00392   TemporaryFile<C>& operator << (TemporaryFile<C>& tf, const T& x) {
00393     (std::fstream&)(tf) << x;
00394     return tf;
00395   }
00396 
00397   class TemporaryFile_path_template : public TemporaryFile<path_template> {
00398   public :
00399     TemporaryFile_path_template(const std::string& directory, const std::string& basename) :
00400       TemporaryFile<path_template>(path_template::Parameter(directory, basename)) {}
00401   };
00402 
00403   class TemporaryFile_basename_template : public TemporaryFile<basename_template> {
00404   public :
00405     TemporaryFile_basename_template(const std::string& basename) :
00406       TemporaryFile<basename_template>(basename_template::Parameter(basename)) {}
00407   };
00408 
00409   class TemporaryFile_self_named : public TemporaryFile<self_named> {
00410   public :
00411     TemporaryFile_self_named(const std::string& name) :
00412       TemporaryFile<self_named>(self_named::Parameter(name)) {}
00413   };
00414  
00415 
00416 
00417   // DEPRICATED -------------------------------------------------
00418   // Warning: If used by multiple processes, TempFile is not safe!
00419   // ------------------------------------------------------------
00420 
00421   class TempFile {
00422     // can not be copied or assigned
00423 
00424   public :
00425 
00426     TempFile() throw(Error_TempFile::open_file, std::ios_base::failure);
00427     TempFile(const std::string& name) throw(Error_TempFile::open_file, std::ios_base::failure);
00428 
00429     operator std::fstream&() throw();
00430     std::fstream& f() throw();
00431 
00432     std::string name() const { return temp_name; }
00433 
00434     ~TempFile() throw(Error_TempFile::remove_file);
00435 
00436   private :
00437 
00438     const std::string temp_name;
00439     std::fstream file;
00440   };
00441 
00442 }
00443 
00444 
00445 // -----------------------------
00446 // Removing lines from files
00447 // -----------------------------
00448 
00449 namespace StreamHandling {
00450 
00451   namespace Error_remove_lines {
00452 
00453     struct temporary_file : Error {
00454       temporary_file(const std::string& what) : Error(what) {}
00455     };
00456   }
00457 
00458   void remove_lines(std::string name, long int n) throw(Error_TempFile::open_file, Error_FileLines::open_file, Error_FileLines::read_file, Error_remove_lines::temporary_file, Error_TempFile::remove_file, std::ios_base::failure, std::bad_alloc) {
00459 
00460     // If n < 0 then the trailing n lines are removed, and
00461     // if n > 0 then the leading n lines are removed;
00462     // for n <> 0 the final line is always concluded with "\n";
00463     // if abs(n) is greater or equal than the number of lines in the file,
00464     // then the file becomes empty.
00465 
00466     if (n == 0)
00467       return;
00468     TempFile t;
00469     {
00470       FileLines f(name);
00471       if (n > 0)
00472   std::copy(f.begin() + n, f.end(), std::ostream_iterator<std::string>(t, "\n"));
00473       else {
00474   std::copy(f.begin(), f.begin() + std::max(f.size() + n, 0L), std::ostream_iterator<std::string>(t, "\n"));
00475       }
00476     }
00477     t.f().seekg(0);
00478     std::ofstream f(name.c_str());
00479     f << t.f().rdbuf();
00480     if (! t.f())
00481       throw Error_remove_lines::temporary_file("StreamHandling::remove_lines : Error when writing to temporary file " + t.name());
00482   }
00483 
00484 }
00485 
00486 // ------------------------------------------
00487 // Pouring the content of a file into a string
00488 // ------------------------------------------
00489 
00490 namespace StreamHandling {
00491 
00492   namespace Error_file2string {
00493 
00494     struct open_file : Error {
00495       open_file(const std::string& what) : Error(what) {}
00496     };
00497   }
00498 
00499   inline std::string file2string(const char* const name) throw(Error_file2string::open_file, std::ios_base::failure) {
00500     std::ifstream f(name);
00501     if (! f)
00502       throw Error_file2string::open_file("StreamHandling::file2string : Can not open file " + std::string(name));
00503     std::ostringstream s;
00504     s << f.rdbuf();
00505     return s.str();
00506   }
00507   inline std::string file2string(const std::string& name) throw(Error_file2string::open_file, std::ios_base::failure) {
00508     return file2string(name.c_str());
00509   }
00510 
00511 }
00512 
00513 // -----------------------------
00514 // Opening an std::ostream object which writes its output
00515 // into a stream given by a Unix file descriptor
00516 // -----------------------------
00517 
00518 // From \cite{Jo1999}, page 672
00519 
00520 namespace StreamHandling {
00521 
00522   class fdoutbuf : public std::streambuf {
00523   protected :
00524     int fd; // file descriptor
00525   public :
00526     fdoutbuf(int _fd) : fd(_fd) {}
00527   protected :
00528     virtual int_type overflow(int_type c) {
00529       if (c != EOF) {
00530   char z = c;
00531   if (write(fd, &z, 1) != 1)
00532     return EOF;
00533       }
00534       return c;
00535     }
00536 
00537     virtual std::streamsize xsputn(const char* s, std::streamsize num) {
00538       return write(fd, s, num);
00539     }
00540   };
00541 
00542   struct fdostream : protected fdoutbuf, public std::ostream {
00543     fdostream(int fd) : fdoutbuf(fd), std::ostream(static_cast<fdoutbuf*>(this))  {}
00544   };
00545 
00546 }
00547 
00548 // --------------------------------------------------------------------------
00549 // Opening a file for writing (appending at the end) so that
00550 // the file is locked for other processes (using fcntl)
00551 // --------------------------------------------------------------------------
00552 
00553 namespace StreamHandling {
00554 
00555   namespace Error_LockFile {
00556 
00557     struct lock_file : Error {
00558       lock_file(const std::string& what) : Error(what) {}
00559     };
00560     struct unlock_file : Error {
00561       unlock_file(const std::string& what) : Error(what) {}
00562     };
00563      struct call_open : Error {
00564       call_open(const std::string& what) : Error(what) {}
00565     };
00566     struct call_close : Error {
00567       call_close(const std::string& what) : Error(what) {}
00568     };
00569   }
00570 
00571   struct LockedFileOstream : fdostream {
00572     LockedFileOstream(const std::string& _name) :
00573       fdostream(open(_name.c_str(), O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)), name(_name)  {
00574       if (fd == -1)
00575   throw Error_LockFile::call_open("StreamHandling::LockedFileOstream::LockedFileOstream(const std::string& _name) : Can not open file " + name);
00576       flock set_lock = { F_WRLCK, 0, SEEK_SET, 0};
00577       if (fcntl(fd, F_SETLKW, &set_lock) == -1)
00578   throw Error_LockFile::lock_file("StreamHandling::LockedFileOstream::LockedFileOstream(const std::string& _name) : Can not lock file " + name);
00579   }
00580     ~LockedFileOstream() {
00581       flock release_lock = { F_UNLCK, 0, SEEK_SET, 0};
00582       if (fcntl(fd, F_SETLK, &release_lock) == -1)
00583   throw Error_LockFile::unlock_file("StreamHandling::LockedFileOstream::~LockedFileOstream(const std::string& _name) : Can not unlock file " + name);
00584       if (close(fd))
00585   throw Error_LockFile::call_open("StreamHandling::LockedFileOstream::~LockedFileOstream(const std::string& _name) : Can not close file " + name);
00586     }
00587     const std::string name;
00588   };
00589 
00590 }
00591 
00592 // ----------------------------------------------------------------------
00593 // Copying files
00594 // ----------------------------------------------------------------------
00595 
00596 namespace StreamHandling {
00597 
00598   bool copy(const std::string& from, const std::string& to) {
00599     std::ifstream in(from.c_str());
00600     std::ofstream out(to.c_str());
00601     out << in.rdbuf();
00602     return in and out;
00603   }
00604 
00605 }
00606 
00607 // ----------------------------------------------------------------------
00608 // Output iterator adapter with field width
00609 // ----------------------------------------------------------------------
00610 
00611 namespace StreamHandling {
00612 
00613   template <typename T, int width>
00614   class Wrapper {
00615     const T& t;
00616   public :
00617     Wrapper(const T& t) : t(t) {}
00618     friend inline std::ostream& operator <<(std::ostream& o, const Wrapper& w) {
00619       return o << std::setw(width) << w.t;
00620     }
00621   };
00622 
00623   template <typename T, int width>
00624   std::ostream_iterator<Wrapper<T, width> > output_iterator(std::ostream& o, const char* sep) {
00625     return std::ostream_iterator<Wrapper<T, width> > (o, sep);
00626   }
00627 
00628 }
00629 
00630 // ----------------------------------------------------------------------
00631 
00632 // -----------------------------
00633 // Implementation of class FileLines
00634 // -----------------------------
00635 
00636 namespace StreamHandling {
00637 
00638   inline FileLines::FileLines(const std::string& f) throw() : filename(f) {}
00639 
00640   inline FileLines::FileLines(const FileLines& f) throw() : filename(f.filename) {}
00641 
00642   inline FileLines& FileLines::operator = (const FileLines& f) throw() {
00643     filename = f.filename;
00644     return *this;
00645   }
00646 
00647   inline bool FileLines::operator == (const FileLines& f) const throw() {
00648     return filename == f.filename;
00649   }
00650 
00651   inline bool FileLines::operator != (const FileLines& f) const throw() {
00652     return filename != f.filename;
00653   }
00654 
00655   inline std::streamsize FileLines::size() const throw(Error_FileLines::open_file, Error_FileLines::read_file, std::ios_base::failure) {
00656     std::ifstream s(filename.c_str());
00657     if (! s)
00658       throw Error_FileLines::open_file("StreamHandling::FileLines::size : Can not open file " + filename);
00659     std::streamsize n = 0;
00660     bool last_character_is_eol = false;
00661     do {
00662       if (s.peek() == std::char_traits<char>::eof()) {
00663   last_character_is_eol = true;
00664   break;
00665       }
00666       s.ignore(std::numeric_limits<int>::max(), '\n');
00667       ++ n;
00668     } while (s);
00669     if (s.bad() or (not last_character_is_eol and not s.eof()))
00670       throw Error_FileLines::read_file("StreamHandling::FileLines::size : Error when reading from file " + filename);
00671     return n;
00672   }
00673 
00674   inline FileLinesInputIterator FileLines::begin() const throw(Error_FileLines::open_file, std::ios_base::failure, std::bad_alloc) {
00675     return FileLinesInputIterator(filename);
00676   }
00677 
00678   inline FileLinesInputIterator FileLines::end() const throw() {
00679     return FileLinesInputIterator();
00680   }
00681 }
00682 
00683 
00684 // -----------------------------
00685 // Implementation of class FileLinesInputIterator
00686 // -----------------------------
00687 
00688 namespace StreamHandling {
00689   
00690   // _impl
00691 
00692   inline FileLinesInputIterator::_impl::_impl (const std::string& filename) throw(Error_FileLines::open_file, std::ios_base::failure) : s(filename.c_str()), current_line(0), last_line_read(-1) {
00693     if (! s)
00694       throw Error_FileLines::open_file("StreamHandling::FileLinesInputIterator::_impl::_impl : Can not open file " + filename);
00695   }
00696 
00697   // private constructors
00698 
00699   inline FileLinesInputIterator::FileLinesInputIterator() throw() : p(0) {}
00700 
00701   inline FileLinesInputIterator::FileLinesInputIterator(const std::string& filename) throw(Error_FileLines::open_file, std::ios_base::failure, std::bad_alloc) : p(new _impl(filename)) {
00702     if (p -> s.peek() == std::char_traits<char>::eof())
00703       p.release();
00704   }
00705 
00706   // copy constructor and assignments
00707 
00708   inline FileLinesInputIterator::FileLinesInputIterator(const FileLinesInputIterator& it) throw() : p(it.p) {}
00709   // fake "const" (but it seems necessary (??))
00710 
00711   inline FileLinesInputIterator& FileLinesInputIterator::operator = (FileLinesInputIterator& it) throw() {
00712       p = it.p;
00713       return *this;
00714   }
00715 
00716   // comparisons
00717 
00718   inline bool FileLinesInputIterator::operator == (const FileLinesInputIterator& it) const throw() {
00719     if (p.get() == 0 and it.p.get() == 0)
00720       return true;
00721     if (p.get() != 0 and it.p.get() != 0)
00722       return p -> current_line == it.p -> current_line;
00723     if (p.get() == 0) {
00724       it.update();
00725       return it.p.get() == 0;
00726     }
00727     else {
00728       update();
00729       return p.get() == 0;
00730     }
00731   }
00732 
00733   inline bool FileLinesInputIterator::operator != (const FileLinesInputIterator& it) const throw() {
00734     return not (*this == it);
00735   }
00736 
00737   // update
00738 
00739   inline void FileLinesInputIterator::update() const throw(Error_FileLines::read_file, std::ios_base::failure) {
00740 
00741     std::ifstream& s(p -> s);
00742     const std::streamsize& current(p -> current_line);
00743     const std::streamsize& currentm1(current - 1);
00744     std::streamsize& last(p -> last_line_read);
00745     const std::streamsize diff = currentm1 - last;
00746 
00747     if (diff == -1)
00748       return;
00749     line_advance(s, diff);
00750     if (s.bad() or (s.fail() and not s.eof()))
00751       throw Error_FileLines::read_file("StreamHandling::FileLinesInputIterator::update : Error when reading the stream");
00752     if (s.eof() or s.peek() == std::char_traits<char>::eof())
00753       p.release();
00754     else
00755       last = currentm1;
00756   }
00757 
00758   // dereference
00759 
00760   inline FileLinesInputIterator::value_type FileLinesInputIterator:: operator *() const throw(Error_FileLines::read_file, std::ios_base::failure) {
00761 
00762     const std::streamsize& current(p -> current_line);
00763     std::streamsize& last(p -> last_line_read);
00764     std::ifstream& s(p -> s);
00765     std::string& l(p -> line);
00766 
00767     if (current == last)
00768       return l;
00769     update();
00770     getline(s, l);
00771     if (s.bad() or (s.fail() and not (s.eof())))
00772       throw Error_FileLines::read_file("StreamHandling::FileLinesInputIterator::operator * : Error when reading the stream");
00773     last = current;
00774     return l;
00775   }
00776 
00777   // pointer arithmetic
00778 
00779   inline FileLinesInputIterator& FileLinesInputIterator::operator++() throw(Error_FileLines::read_file, std::ios_base::failure) {
00780 
00781     ++(p -> current_line);
00782     update();
00783     return *this;
00784   }
00785 
00786   inline FileLinesInputIterator&  FileLinesInputIterator::operator+(unsigned long int n) throw() {
00787     p -> current_line += n;
00788     return *this;
00789   }
00790 }
00791 
00792 
00793 // -----------------------------
00794 // Implementation of class TempFile
00795 // -----------------------------
00796 
00797 namespace StreamHandling {
00798 
00799   inline TempFile::TempFile() throw(Error_TempFile::open_file, std::ios_base::failure) : temp_name(const_cast<const char*>(std::tmpnam(0))), file(temp_name.c_str(), std::ios::in | std::ios::out | std::ios::trunc) {
00800     if (! file)
00801       throw Error_TempFile::open_file("StreamHandling::TempFile::TempFile : Can not open file " + temp_name);
00802   }
00803 
00804   inline TempFile::TempFile(const std::string& name) throw(Error_TempFile::open_file, std::ios_base::failure) : temp_name(name.c_str()), file(temp_name.c_str(), std::ios::in | std::ios::out | std::ios::trunc) {
00805     if (! file)
00806       throw Error_TempFile::open_file("StreamHandling::TempFile::TempFile : Can not open file " + temp_name);
00807   }
00808 
00809   inline TempFile::operator std::fstream&() throw() {
00810     return file;
00811   }
00812   inline std::fstream& TempFile::f() throw() {
00813     return file;
00814   }
00815 
00816   inline TempFile::~TempFile() throw(Error_TempFile::remove_file) {
00817     if (std::remove(temp_name.c_str()))
00818       throw Error_TempFile::remove_file("StreamHandling::TempFile::TempFile : Can not remove file " + temp_name);
00819   }
00820 
00821 }
00822 
00823 
00824 
00825 #endif