OKlibrary
0.2.1.6
|
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