|
yast2-core
|
00001 00013 #ifndef __IniParser_h__ 00014 #define __IniParser_h__ 00015 00016 #include <unistd.h> 00017 #include <ctype.h> 00018 #include <stdio.h> 00019 #include <regex.h> 00020 #include <locale.h> 00021 00022 #include <y2util/RepDef.h> 00023 #include <YCP.h> 00024 00025 #include <iosfwd> 00026 #include <fstream> 00027 #include <string> 00028 #include <vector> 00029 #include <set> 00030 00031 #include "IniFile.h" 00032 00033 using std::string; 00034 using std::vector; 00035 using std::ifstream; 00036 using std::ofstream; 00037 using std::set; 00038 00039 DEFINE_BASE_POINTER (Regex_t); 00040 00041 #pragma GCC visibility push(hidden) 00042 00044 // It is restored when we go out of scope. 00045 class TemporaryLocale 00046 { 00047 public: 00048 TemporaryLocale (int category, const char * locale); 00049 ~TemporaryLocale (); 00050 private: 00052 char *my_setlocale(int category, const char *locale); 00053 00054 int _category; 00055 char * _oldlocale; 00056 }; 00057 #pragma GCC visibility pop 00058 00063 class Regex_t : virtual public Rep 00064 { 00065 REP_BODY (Regex_t); 00066 private: 00067 friend class Regex; 00068 00069 regex_t regex; 00070 bool live; 00071 00072 public: 00073 Regex_t (): 00074 live (false) {} 00075 ~Regex_t () { 00076 if (live) 00077 { 00078 regfree (®ex); 00079 } 00080 } 00088 int compile (const string& pattern, bool ignore_case) { 00089 int ret = -1; 00090 if (live) 00091 { 00092 y2error ("Regex_t @%p already compiled", this); 00093 } 00094 else 00095 { 00096 // #177560: [A-Za-z] excludes some ASCII letters in Estonian 00097 TemporaryLocale tl (LC_ALL, "C"); 00098 00099 ret = regcomp (®ex, pattern.c_str (), 00100 REG_EXTENDED | (ignore_case ? REG_ICASE : 0)); 00101 if (ret) 00102 { 00103 char error[256]; 00104 regerror (ret, ®ex, error, 256); 00105 y2error ("Regex_t %s error: %s", pattern.c_str (), error); 00106 } 00107 else 00108 { 00109 live = true; 00110 } 00111 } 00112 return ret; 00113 } 00114 }; 00115 00119 class Regex 00120 { 00121 Regex_tPtr rxtp; 00122 public: 00123 Regex (): rxtp (0) {} 00130 int compile (const string& pattern, bool ignore_case) { 00131 if (rxtp) 00132 { 00133 y2error ("Regex_t @%p already compiled", this); 00134 return -1; 00135 } 00136 else 00137 { 00138 rxtp = new Regex_t; 00139 return rxtp->compile (pattern, ignore_case); 00140 } 00141 } 00142 const regex_t * regex () const { return & rxtp->regex; } 00143 }; 00144 00148 class RegexMatch 00149 { 00150 public: 00152 vector<string> matches; 00154 string rest; 00155 00157 const string& operator[] (size_t i) { return matches[i]; } 00159 operator bool () { return matches.size () > 0; } 00160 00166 RegexMatch (const Regex& rx, const string& s, size_t nmatch = 20) { 00167 // allocate at least for the whole match 00168 if (nmatch == 0) 00169 { 00170 nmatch = 1; 00171 } 00172 regmatch_t rm_matches[nmatch]; 00173 if (0 == regexec (rx.regex (), s.c_str (), nmatch, rm_matches, 0)) 00174 { 00175 // match 00176 matches.reserve (nmatch); 00177 rest = s.substr (0, rm_matches[0].rm_so) + 00178 s.substr (rm_matches[0].rm_eo); 00179 } 00180 else 00181 { 00182 // no match 00183 rm_matches[0].rm_so = -1; 00184 rest = s; 00185 } 00186 00187 size_t i; 00188 for (i = 0; i < nmatch && rm_matches[i].rm_so != -1; ++i) 00189 { 00190 matches.push_back (s.substr (rm_matches[i].rm_so, 00191 rm_matches[i].rm_eo - rm_matches[i].rm_so)); 00192 } 00193 } 00194 00195 }; 00196 00200 struct IoPattern 00201 { 00202 Regex rx; 00203 string out; 00204 }; 00205 00209 struct section 00210 { 00211 IoPattern begin; 00212 IoPattern end; 00213 bool end_valid; 00214 }; 00215 00219 struct param 00220 { 00222 IoPattern line; 00224 Regex begin; 00226 Regex end; 00228 bool multiline_valid; 00229 }; 00230 00232 struct FileDescr 00233 { 00237 string fn; 00241 string sn; 00245 time_t timestamp; 00246 FileDescr (char*fn); 00247 bool changed (); 00248 FileDescr () {} 00249 }; 00250 00254 class IniParser 00255 { 00256 private: 00260 time_t timestamp; 00265 map<string,FileDescr> multi_files; 00269 string file; 00273 time_t getTimeStamp(); 00275 bool line_can_continue; 00277 bool ignore_case_regexps; 00279 bool ignore_case; 00281 bool prefer_uppercase; 00286 bool first_upper; 00288 bool no_nested_sections; 00290 bool global_values; 00292 bool repeat_names; 00294 bool comments_last; 00296 bool join_multiline; 00298 bool no_finalcomment_kill; 00300 bool read_only; 00302 bool flat; 00303 00305 string subindent; 00309 vector<Regex> linecomments; 00313 vector<Regex> comments; 00317 vector<section> sections; 00321 vector<param> params; 00325 vector<IoPattern> rewrites; 00326 00330 ifstream scanner; 00334 string scanner_file; 00338 int scanner_line; 00339 00344 bool started; 00345 00349 bool multiple_files; 00353 vector<string> files; 00354 00358 int scanner_start(const char*fn); 00362 void scanner_stop(); 00366 int scanner_get(string&s); 00367 00371 int parse_helper(IniSection&ini); 00375 int write_helper(IniSection&ini, ofstream&of,int depth); 00376 public: 00387 set<string> deleted_sections; 00391 IniSection inifile; 00392 // apparently the uninitialized members are filled in 00393 // by the grammar definition 00394 IniParser () : 00395 linecomments (), comments (), 00396 sections (), params (), rewrites (), 00397 started (false), multiple_files (false), 00398 // inifile ("toplevel") 00399 inifile (this) 00400 {} 00401 ~IniParser (); 00406 void initFiles (const char*fn); 00411 void initFiles (const YCPList&f); 00417 int initMachine (const YCPMap&scr); 00418 bool isStarted() { return started; } 00419 00424 int parse(); 00429 void UpdateIfModif (); 00430 00434 int write (); 00435 00441 bool sectionNeedsEnd (int i) { return sections[i].end_valid; } 00442 00450 string getFileName (const string&sec, int rb) const; 00454 bool HaveRewrites () const { return rewrites.size () > 0; } 00455 00457 bool repeatNames () const { return repeat_names; } 00459 bool isFlat () const { return flat; } 00460 00466 string changeCase (const string&str) const; 00467 }; 00468 00469 #endif//__IniParser_h__
1.7.3