IniParser.h

Go to the documentation of this file.
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 (&regex);
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 (&regex, pattern.c_str (),
00100                            REG_EXTENDED | (ignore_case ? REG_ICASE : 0));
00101             if (ret)
00102             {
00103                 char error[256];
00104                 regerror (ret, &regex, 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__

Generated on Tue Nov 6 01:20:21 2007 for yast2-core by  doxygen 1.5.0