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
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
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
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
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
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
00393
00394 IniParser () :
00395 linecomments (), comments (),
00396 sections (), params (), rewrites (),
00397 started (false), multiple_files (false),
00398
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__