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
00021 #include <y2util/RepDef.h>
00022 #include <YCP.h>
00023
00024 #include <iosfwd>
00025 #include <fstream>
00026 #include <string>
00027 #include <vector>
00028 #include <set>
00029
00030 #include "IniFile.h"
00031
00032 using std::string;
00033 using std::vector;
00034 using std::ifstream;
00035 using std::ofstream;
00036 using std::set;
00037
00038 DEFINE_BASE_POINTER (Regex_t);
00039
00044 class Regex_t : virtual public Rep
00045 {
00046 REP_BODY (Regex_t);
00047 private:
00048 friend class Regex;
00049
00050 regex_t regex;
00051 bool live;
00052
00053 public:
00054 Regex_t ():
00055 live (false) {}
00056 ~Regex_t () {
00057 if (live)
00058 {
00059 regfree (®ex);
00060 }
00061 }
00069 int compile (const string& pattern, bool ignore_case) {
00070 int ret = -1;
00071 if (live)
00072 {
00073 y2error ("Regex_t @%p already compiled", this);
00074 }
00075 else
00076 {
00077 ret = regcomp (®ex, pattern.c_str (),
00078 REG_EXTENDED | (ignore_case ? REG_ICASE : 0));
00079 if (ret)
00080 {
00081 char error[256];
00082 regerror (ret, ®ex, error, 256);
00083 y2error ("Regex_t %s error: %s", pattern.c_str (), error);
00084 }
00085 else
00086 {
00087 live = true;
00088 }
00089 }
00090 return ret;
00091 }
00092 };
00093
00097 class Regex
00098 {
00099 Regex_tPtr rxtp;
00100 public:
00101 Regex (): rxtp (0) {}
00108 int compile (const string& pattern, bool ignore_case) {
00109 if (rxtp)
00110 {
00111 y2error ("Regex_t @%p already compiled", this);
00112 return -1;
00113 }
00114 else
00115 {
00116 rxtp = new Regex_t;
00117 return rxtp->compile (pattern, ignore_case);
00118 }
00119 }
00120 const regex_t * regex () const { return & rxtp->regex; }
00121 };
00122
00126 class RegexMatch
00127 {
00128 public:
00130 vector<string> matches;
00132 string rest;
00133
00135 const string& operator[] (size_t i) { return matches[i]; }
00137 operator bool () { return matches.size () > 0; }
00138
00144 RegexMatch (const Regex& rx, const string& s, size_t nmatch = 20) {
00145
00146 if (nmatch == 0)
00147 {
00148 nmatch = 1;
00149 }
00150 regmatch_t rm_matches[nmatch];
00151 if (0 == regexec (rx.regex (), s.c_str (), nmatch, rm_matches, 0))
00152 {
00153
00154 matches.reserve (nmatch);
00155 rest = s.substr (0, rm_matches[0].rm_so) +
00156 s.substr (rm_matches[0].rm_eo);
00157 }
00158 else
00159 {
00160
00161 rm_matches[0].rm_so = -1;
00162 rest = s;
00163 }
00164
00165 size_t i;
00166 for (i = 0; i < nmatch && rm_matches[i].rm_so != -1; ++i)
00167 {
00168 matches.push_back (s.substr (rm_matches[i].rm_so,
00169 rm_matches[i].rm_eo - rm_matches[i].rm_so));
00170 }
00171 }
00172
00173 };
00174
00178 struct IoPattern
00179 {
00180 Regex rx;
00181 string out;
00182 };
00183
00187 struct section
00188 {
00189 IoPattern begin;
00190 IoPattern end;
00191 bool end_valid;
00192 };
00193
00197 struct param
00198 {
00200 IoPattern line;
00202 Regex begin;
00204 Regex end;
00206 bool multiline_valid;
00207 };
00208
00209 struct FileDescr
00210 {
00214 string fn;
00218 string sn;
00222 time_t timestamp;
00223 FileDescr (char*fn);
00224 bool changed ();
00225 FileDescr () {}
00226 };
00227
00231 class IniParser
00232 {
00233 private:
00237 time_t timestamp;
00242 map<string,FileDescr> multi_files;
00246 string file;
00250 time_t getTimeStamp();
00252 bool line_can_continue;
00254 bool ignore_case_regexps;
00256 bool ignore_case;
00258 bool prefer_uppercase;
00263 bool first_upper;
00265 bool no_nested_sections;
00267 bool global_values;
00269 bool repeat_names;
00271 bool comments_last;
00273 bool join_multiline;
00275 bool no_finalcomment_kill;
00277 bool read_only;
00279 bool flat;
00280
00282 string subindent;
00286 vector<Regex> linecomments;
00290 vector<Regex> comments;
00294 vector<section> sections;
00298 vector<param> params;
00302 vector<IoPattern> rewrites;
00303
00307 ifstream scanner;
00311 int scanner_line;
00312
00317 bool started;
00318
00322 bool multiple_files;
00326 vector<string> files;
00327
00331 int scanner_start(const char*fn);
00335 void scanner_stop();
00339 int scanner_get(string&s);
00340
00344 int parse_helper(IniSection&ini);
00348 int write_helper(IniSection&ini, ofstream&of,int depth);
00349 public:
00360 set<string> deleted_sections;
00364 IniSection inifile;
00365
00366
00367 IniParser () :
00368 linecomments (), comments (),
00369 sections (), params (), rewrites (),
00370 started (false), multiple_files (false),
00371
00372 inifile (this)
00373 {}
00374 ~IniParser ();
00379 void initFiles (const char*fn);
00384 void initFiles (const YCPList&f);
00390 int initMachine (const YCPMap&scr);
00391 bool isStarted() { return started; }
00392
00397 int parse();
00402 void UpdateIfModif ();
00403
00407 int write ();
00408
00414 bool sectionNeedsEnd (int i) { return sections[i].end_valid; }
00415
00423 string getFileName (const string&sec, int rb);
00427 bool HaveRewrites () const { return rewrites.size () > 0; }
00428
00430 bool repeatNames () const { return repeat_names; }
00432 bool isFlat () const { return flat; }
00433
00439 string changeCase (const string&str) const;
00440 };
00441
00442 #endif//__IniParser_h__