Added exec_prefix to the .pc.in file
[libconfigfile.git] / src / configfile.cc
blob68acd9010aad5f991b1f506340a5d2994171fefb
1 /*******************************************************************************
2 ********************************************************************************
4 Copyright (c) 2008 Ahmed S. Badran
6 Filename: configfile.cc
7 Description: Implementation.
8 Created: 08/12/2008 10:27:53 PM PDT
9 Revision: $Rev$
10 Author: Ahmed S. Badran (Ahmed B.), ahmed.badran@gmail.com
12 ********************************************************************************
13 *******************************************************************************/
14 #include "configfile.h"
15 using namespace std;
17 configfile::configfile(const string& fpath):
18 file_path(fpath)
20 unsigned MAX = 4096;
21 char* buf = new char[MAX];
22 FILE* filp = fopen(file_path.c_str(), "r");
23 if (!filp)
24 return;
25 string secname = "", key = "", value = "";
26 while (getline(&buf, &MAX, filp) != -1) {
27 if (is_comment(buf)) {
28 /* drop it */
29 } else if (is_section_header(buf, &secname)) {
30 add_section(secname);
31 } else if (is_key_value(buf, &key, &value)) {
32 if (secname != "") {
33 add_key(secname, key, value);
35 } else {
36 /* drop it too */
38 memset(buf, 0, MAX);
40 fclose(filp);
41 filp = 0;
44 vector<string>
45 configfile::get_sections () const
47 vector<string> section_names;
48 data_struct::const_iterator pos;
49 data_struct::const_iterator end = sections.end();
50 for (pos = sections.begin(); pos != end; ++pos) {
51 section_names.push_back(pos->first);
53 return section_names;
56 vector<string>
57 configfile::get_keys (const string& secname) const
59 unsigned index = 0;
60 vector<string> keys;
61 if (!get_section_index(secname, &index)) {
62 return keys;
64 const vector<pair<string, string> >& key_values =
65 sections[index].second;
66 vector<pair<string, string> >::const_iterator pos;
67 vector<pair<string, string> >::const_iterator end = key_values.end();
68 for (pos = key_values.begin(); pos != end; ++pos) {
69 keys.push_back(pos->first);
71 return keys;
74 bool
75 configfile::get_key_value (const string& secname, const string& key, string*
76 value) const
78 unsigned index = 0;
79 if (!get_section_index(secname, &index)) {
80 return false;
82 const vector<pair<string, string> >& key_values =
83 sections[index].second;
84 vector<pair<string, string> >::const_iterator pos;
85 vector<pair<string, string> >::const_iterator end = key_values.end();
86 for (pos = key_values.begin(); pos != end; ++pos) {
87 if (pos->first == key) {
88 *value = pos->second;
89 return true;
92 return false;
95 void
96 configfile::add_section (const string& name)
98 vector<pair<string, string> > empty;
99 sections.push_back(make_pair(name, empty));
102 bool
103 configfile::add_key (const string& secname, const string& key, const string&
104 value)
106 unsigned index = 0;
107 if (!get_section_index(secname, &index)) {
108 return false;
110 vector<pair<string, string> >& key_values = sections[index].second;
111 key_values.push_back(make_pair(key, value));
112 return true;
115 bool
116 configfile::get_section_index (const string& secname, unsigned* index) const
118 unsigned i = 0;
119 unsigned section_count = sections.size();
120 for (i = 0; i < section_count; ++i) {
121 if (sections[i].first == secname) {
122 *index = i;
123 return true;
126 return false;
129 bool
130 configfile::is_comment (const char* buf) const
132 bool retval;
133 regex_t regex;
134 regcomp(&regex, "^[ ]*#.*$", REG_EXTENDED);
135 if (regexec(&regex, buf, 0, 0, 0) == 0) {
136 retval = true;
137 } else {
138 retval = false;
140 regfree(&regex);
141 return retval;
143 bool
144 configfile::is_section_header(const char* buf, string* secname) const
146 const unsigned MAX = 1024;
147 regmatch_t substr[3];
148 char tmpbuf[MAX] = {0};
149 memset(substr, 0, sizeof(substr));
150 regex_t regex;
151 regcomp(&regex, "^[ ]*\\[[ ]*([^ ]+)[ ]+\"([^ ]+)\""
152 "[ ]*\\][ ]*$", REG_EXTENDED | REG_NEWLINE);
153 if (regexec(&regex, buf, 3, substr, 0) == 0) {
154 memset(tmpbuf, 0, MAX);
155 extract_field(1, substr, buf, tmpbuf);
156 *secname = tmpbuf;
157 *secname += ".";
158 memset(tmpbuf, 0, MAX);
159 extract_field(2, substr, buf, tmpbuf);
160 *secname += tmpbuf;
161 regfree(&regex);
162 return true;
165 regcomp(&regex, "^[ ]*\\[[ ]*([^ ]+)[ ]*\\][ ]*$",
166 REG_EXTENDED | REG_NEWLINE);
167 if (regexec(&regex, buf, 3, substr, 0) == 0) {
168 memset(tmpbuf, 0, MAX);
169 extract_field(1, substr, buf, tmpbuf);
170 *secname = tmpbuf;
171 regfree(&regex);
172 return true;
174 return false;
177 bool
178 configfile::is_key_value(const char* buf, string* key, string* value) const
180 const unsigned MAX = 1024;
181 regmatch_t substr[3];
182 char tmpbuf[MAX] = {0};
183 memset(substr, 0, sizeof(substr));
184 regex_t regex;
185 regcomp(&regex, "^[ ]*([^ ].*[^ ])[ ]*=[ ]*"
186 "([^ ].*[^ ])[ ]*$", REG_EXTENDED | REG_NEWLINE);
187 if (regexec(&regex, buf, 3, substr, 0) == 0) {
188 memset(tmpbuf, 0, MAX);
189 extract_field(1, substr, buf, tmpbuf);
190 *key = tmpbuf;
191 memset(tmpbuf, 0, MAX);
192 extract_field(2, substr, buf, tmpbuf);
193 *value = tmpbuf;
194 return true;
196 return false;
199 void
200 configfile::extract_field (unsigned i, regmatch_t* regex_arr, const char*
201 inbuf, char* outbuf) const
203 strncpy(outbuf, &inbuf[regex_arr[i].rm_so], regex_arr[i].rm_eo -
204 regex_arr[i].rm_so);
207 bool
208 configfile::save_to (const string& fpath) const
210 FILE* filp = fopen(fpath.c_str(), "w");
211 if (!filp) {
212 return false;
214 data_struct::const_iterator pos;
215 data_struct::const_iterator end = sections.end();
216 string tmp1, tmp2;
217 unsigned index = 0;
218 for (pos = sections.begin(); pos != end; ++pos) {
219 index = pos->first.find('.', 0);
220 if (index != string::npos) {
221 tmp1 = pos->first.substr(0, index);
222 tmp2 = pos->first.substr(index + 1);
223 fprintf(filp, "[%s \"%s\"]\n", tmp1.c_str(),
224 tmp2.c_str());
225 } else {
226 fprintf(filp, "[%s]\n", pos->first.c_str());
228 const vector<pair<string, string> >& key_values = pos->second;
229 vector<pair<string, string> >::const_iterator kpos;
230 vector<pair<string, string> >::const_iterator kend =
231 key_values.end();
232 for (kpos = key_values.begin(); kpos != kend; ++kpos) {
233 fprintf(filp, "\t%s = %s\n", kpos->first.c_str(),
234 kpos->second.c_str());
237 fclose(filp);
238 return true;
241 bool
242 configfile::save ()
244 return save_to(file_path);
247 configfile::~configfile ()