jigdo API
Last update by Admin on 2010-05-23
util/configfile.hh
Go to the documentation of this file.00001 /* $Id: configfile.hh,v 1.2 2003/09/27 21:31:04 atterer Exp $ -*- C++ -*- 00002 __ _ 00003 |_) /| Copyright (C) 2001-2002 | richard@ 00004 | \/¯| Richard Atterer | atterer.net 00005 ¯ '` ¯ 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License, version 2. See 00008 the file COPYING for details. 00009 00010 */ 00066 #ifndef CONFIGFILE_HH 00067 #define CONFIGFILE_HH 00068 00069 #include <iosfwd> 00070 #include <list> 00071 #include <string> 00072 00073 #include <debug.hh> 00074 //______________________________________________________________________ 00075 00084 class ConfigFile { 00085 public: 00086 class ProgressReporter; 00087 class iterator; 00088 inline ConfigFile(ProgressReporter& pr = noReport); 00089 ~ConfigFile(); 00090 00098 void rescan(bool printErrors = false); 00099 00101 void setReporter(ProgressReporter& pr) { reporter = ≺ } 00102 00104 istream& get(istream& s); 00106 ostream& put(ostream& s) const; 00107 //______________________________ 00108 00110 inline iterator firstSection() { return iterator(*firstSect()); } 00112 inline iterator firstSection(const string& sectName); 00113 00115 typedef string& reference; 00116 typedef const string& const_reference; 00117 00118 size_t size() const { return lineCount; } 00119 bool empty() const { return size() == 0; } 00120 00121 inline iterator begin(); 00122 //inline const_iterator begin() const; 00123 inline iterator end(); 00124 //inline const_iterator end() const; 00125 inline reference front(); 00126 //inline const_reference front() const; 00127 inline reference back(); 00128 //inline const_reference back() const; 00129 00130 // Return iterator to first such line in section, or end() 00131 iterator find(const string& sectName, const string& line); 00132 00133 // Insert empty line before pos 00134 inline iterator insert(iterator pos); 00135 // Insert s before pos 00136 inline iterator insert(iterator pos, const_reference s); 00137 inline iterator insert(iterator pos, const char* s); 00138 // Delete line at pos from list; pos becomes invalid 00139 inline iterator erase(iterator pos); 00140 //inline iterator erase(iterator first, iterator last); 00141 // Add line at end of list 00142 inline void push_back(); // Empty line 00143 inline void push_back(const string& s); 00144 inline void push_back(const char* s); 00145 //______________________________ 00146 00150 static inline bool advanceWhitespace(string::const_iterator& x, 00151 const string::const_iterator& end); 00152 static inline bool advanceWhitespace(string::iterator& x, 00153 const string::const_iterator& end); 00155 static inline bool isWhitespace(char x) { return x == ' ' || x == '\t'; } 00156 00169 template<class Container> // E.g. vector<string>; anything with push_back() 00170 static void split(Container& out, const string& s, size_t offset = 0); 00176 static string& quote(string& s); 00177 00178 private: 00179 struct Line { 00180 Line() : prev(), next(), nextSect(0), text() { } 00181 Line(const string& s) : prev(), next(), nextSect(0), text(s) { } 00182 Line(const char* s) : prev(), next(), nextSect(0), text(s) { } 00183 // Returns true if *this is the end() element 00184 bool isEnd() const { return nextSect != 0 && text.empty(); } 00185 Line* prev; 00186 Line* next; 00187 // Linked ring of [section] lines, or null for non-section lines 00188 Line* nextSect; 00189 string text; 00190 }; 00191 ProgressReporter* reporter; 00192 // Disallow copying - copy ctor is never defined 00193 inline ConfigFile(const ConfigFile&); 00194 /* Dummy element for end(). Its "next" ptr points to the first, its 00195 "prev" ptr to the last element, i.e. doubly linked ring of Line 00196 objects. Its nextSect is ptr to linked ring of [section] lines, 00197 or ptr to endElem itself if no sections present. */ 00198 Line endElem; 00199 size_t lineCount; 00200 Line*& firstSect() { return endElem.nextSect; } 00201 00203 static bool split1Word(string* word, const string& s, 00204 string::const_iterator& e); 00205 00207 static ProgressReporter noReport; 00208 00209 public: 00210 //______________________________ 00211 00214 class iterator { 00215 friend class ConfigFile; 00216 public: 00217 iterator() { } 00218 iterator(const iterator& i) : p(i.p) { } 00219 iterator& operator=(const iterator& i) { p = i.p; return *this; } 00220 // Default dtor 00221 reference operator*() const { return p->text; } 00222 reference operator*() { return p->text; } 00223 string* operator->() const { return &p->text; } 00224 string* operator->() { return &p->text; } 00225 iterator& operator++() { p = p->next; return *this; } 00226 iterator& operator--() { p = p->prev; return *this; } 00227 bool operator==(const iterator i) const { return p == i.p; } 00228 bool operator!=(const iterator i) const { return p != i.p; } 00230 bool isSection() const { return p->nextSect != 0; } 00232 bool isSection(const string& sectName) const; 00238 inline iterator& nextSection(); 00243 iterator& nextSection(const string& sectName); 00247 inline bool nextLabel(); 00249 inline bool prevLabel(); 00257 size_t nextLabel(const string& labelName); 00262 bool setLabelOffsets(size_t& begin, size_t& end, size_t& value); 00263 private: 00264 iterator(Line& l) : p(&l) { } 00265 Line*& nextSect() { return p->nextSect; } 00266 Line* p; 00267 }; 00268 //______________________________ 00269 00293 class Find { 00294 public: 00295 // Default copy ctor, dtor 00309 Find(ConfigFile* c, const string& sectName, const string& labelName, 00310 const iterator i, size_t* offset = 0); 00311 Find(ConfigFile* c, const string& sectName, const string& labelName, 00312 size_t* offset = 0); 00318 size_t next(); 00320 iterator section() const { return sectionIter; } 00322 iterator label() const { return labelIter; } 00324 bool finished() const { return labelIter == configFile->end(); } 00325 private: 00326 ConfigFile* configFile; 00327 const string& sectionStr; 00328 const string& labelStr; 00329 iterator sectionIter; // For section line 00330 iterator labelIter; // For label line 00331 bool rightSection; 00332 }; 00333 // TODO: Find_const, which works on a const ConfigFile... 00334 }; 00335 //______________________________________________________________________ 00336 00339 class ConfigFile::ProgressReporter { 00340 public: 00341 virtual ~ProgressReporter() { } 00344 virtual void error(const string& message, const size_t lineNr = 0); 00348 virtual void info(const string& message, const size_t lineNr = 0); 00349 }; 00350 //______________________________________________________________________ 00351 00352 ConfigFile::ConfigFile(ProgressReporter& pr) 00353 : reporter(&pr), endElem(), lineCount(0) { 00354 endElem.prev = &endElem; 00355 endElem.next = &endElem; 00356 endElem.nextSect = &endElem; 00357 } 00358 00359 bool ConfigFile::advanceWhitespace(string::const_iterator& x, 00360 const string::const_iterator& end) { 00361 while (true) { 00362 if (x == end || *x == '#') return true; 00363 if (*x != ' ' && *x != '\t') return false; 00364 ++x; 00365 } 00366 } 00367 bool ConfigFile::advanceWhitespace(string::iterator& x, 00368 const string::const_iterator& end) { 00369 while (true) { 00370 if (x == end || *x == '#') return true; 00371 if (*x != ' ' && *x != '\t') return false; 00372 ++x; 00373 } 00374 } 00375 00376 ConfigFile::iterator& ConfigFile::iterator::nextSection() { 00377 // p automatically ends up pointing to end() 00378 if (isSection()) { 00379 p = p->nextSect; 00380 } else { 00381 do p = p->next; while (!isSection()); 00382 } 00383 return *this; 00384 } 00385 00386 bool ConfigFile::iterator::nextLabel() { 00387 while (true) { 00388 ++*this; 00389 if (isSection()) return false; 00390 // Next line is superfluous cos endElem.isSection() == true 00391 //if (p->isEnd()) return false; 00392 00393 /* Skip any empty line. If there is *any* character on this line, 00394 it must be a label line; it cannot be a section line because 00395 isSection() == false above */ 00396 string::const_iterator x = p->text.begin(); 00397 if (!advanceWhitespace(x, p->text.end())) return true; 00398 } 00399 } 00400 00401 bool ConfigFile::iterator::prevLabel() { 00402 while (true) { 00403 --*this; 00404 if (isSection()) return false; 00405 string::const_iterator x = p->text.begin(); 00406 if (!advanceWhitespace(x, p->text.end())) return true; 00407 } 00408 } 00409 00410 ConfigFile::iterator ConfigFile::firstSection(const string& sectName) { 00411 iterator i = end(); 00412 i.nextSection(sectName); 00413 return i; 00414 } 00415 00416 ConfigFile::iterator ConfigFile::begin() { return iterator(*endElem.next); } 00417 ConfigFile::iterator ConfigFile::end() { return iterator(endElem); } 00418 ConfigFile::reference ConfigFile::front() { return endElem.next->text; } 00419 ConfigFile::reference ConfigFile::back() { return endElem.prev->text; } 00420 00421 ConfigFile::iterator ConfigFile::insert(iterator pos) { 00422 Line* x = new Line(); 00423 x->prev = pos.p->prev; x->next = pos.p; 00424 pos.p->prev->next = x; pos.p->prev = x; 00425 ++lineCount; 00426 return pos; 00427 } 00428 ConfigFile::iterator ConfigFile::insert(iterator pos, const_reference s) { 00429 Line* x = new Line(s); 00430 x->prev = pos.p->prev; x->next = pos.p; 00431 pos.p->prev->next = x; pos.p->prev = x; 00432 ++lineCount; 00433 return pos; 00434 } 00435 ConfigFile::iterator ConfigFile::insert(iterator pos, const char* s) { 00436 Line* x = new Line(s); 00437 x->prev = pos.p->prev; x->next = pos.p; 00438 pos.p->prev->next = x; pos.p->prev = x; 00439 ++lineCount; 00440 return pos; 00441 } 00442 ConfigFile::iterator ConfigFile::erase(iterator pos) { 00443 Paranoid(pos.p != 0); // Don't erase an element twice 00444 Paranoid(!pos.p->isEnd()); // Don't c.erase(c.end()) 00445 pos.p->next->prev = pos.p->prev; 00446 pos.p->prev->next = pos.p->next; 00447 --lineCount; 00448 delete pos.p; 00449 pos.p = 0; 00450 return pos; 00451 } 00452 void ConfigFile::push_back() { 00453 insert(iterator(endElem)); 00454 } 00455 void ConfigFile::push_back(const string& s) { 00456 insert(iterator(endElem)); 00457 back() = s; 00458 } 00459 void ConfigFile::push_back(const char* s) { 00460 insert(iterator(endElem)); 00461 back() = s; 00462 } 00463 //______________________________________________________________________ 00464 00465 inline ostream& operator<<(ostream& s, const ConfigFile& c) { 00466 return c.put(s); 00467 } 00468 inline istream& operator>>(istream& s, ConfigFile& c) { 00469 return c.get(s); 00470 } 00471 //______________________________________________________________________ 00472 00473 template<class Container> 00474 void ConfigFile::split(Container& out, const string& s, size_t offset) { 00475 string word; 00476 string::const_iterator e = s.begin() + offset; 00477 while (split1Word(&word, s, e)) { 00478 out.push_back(string()); 00479 swap(word, out.back()); 00480 } 00481 } 00482 00483 #endif
Generated on Tue Sep 23 14:27:41 2008 for jigdo by
