source: trunk/lib/Configuration.cc @ 516

Last change on this file since 516 was 516, checked in by Peter Johansson, 14 years ago

adding filename translations in Configuration class. Before checking what type parsing to use, filename is translated according to rules set in config file. Default rule (as before) is to remove trailing .in from filenames. To solve the parsing I added a simple regexp function - see utility.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.8 KB
Line 
1// $Id: Configuration.cc 516 2007-12-09 07:58:54Z peter $
2
3/*
4  Copyright (C) 2007 Peter Johansson
5
6  This file is part of svndigest, http://trac.thep.lu.se/trac/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "Configuration.h"
25
26#include "Functor.h"
27
28#include <cassert>
29#include <fstream>
30#include <map>
31#include <string>
32#include <sstream>
33#include <stdexcept>
34#include <utility>
35
36namespace theplu{
37namespace svndigest{
38
39  Configuration* Configuration::instance_=NULL;
40
41
42  Configuration::Configuration(void)
43  {
44  }
45
46
47  void Configuration::add_codon(std::string key, std::string start, 
48                                std::string end)
49  {
50    std::pair<std::string, std::string> p(start,end);
51    String2Codons::iterator iter = string2codons_.end();
52    for (String2Codons::iterator i=string2codons_.begin();
53         i!=string2codons_.end(); ++i)
54      if (i->first == key)
55        iter = i;
56   
57    if (iter==string2codons_.end())
58      string2codons_.push_back(std::make_pair(key, VectorPair(1,p)));
59    else
60      iter->second.push_back(p);
61  }
62
63
64  const std::vector<std::pair<std::string, std::string> >* 
65  Configuration::codon(std::string file_name) const 
66  {
67    if (const std::pair<std::string,std::string>* dict=dictionary(file_name))
68      try {
69        file_name = translate(file_name, *dict);
70      }
71      catch (std::runtime_error& e) {
72        std::stringstream mess;
73        mess << "svndigest: invalid config file: "
74             << "expression " << dict->second << " is invalid";
75        if (e.what()[0])
76          mess << "because " << e.what() << " is a too large.";
77        else
78          mess << ".";
79        throw std::runtime_error(mess.str());
80      }
81    for (String2Codons::const_iterator i(string2codons_.begin());
82         i!=string2codons_.end(); ++i) {
83      if (svndigest::equal(file_name.begin(), file_name.end(), 
84                           i->first.begin(), i->first.end()) ) {
85        return &i->second;
86      }
87    }
88    return NULL;
89  }
90
91
92  const std::map<std::string,Alias>& Configuration::copyright_alias(void) const
93  {
94    return copyright_alias_;
95  }
96
97
98  const std::pair<std::string,std::string>* 
99  Configuration::dictionary(std::string lhs) const
100  {
101    for (size_t i=0; i<dictionary_.size(); ++i)
102      if (svndigest::equal(lhs.begin(), lhs.end(), 
103                           dictionary_[i].first.begin(),
104                           dictionary_[i].first.end()))
105        return &dictionary_[i];
106    return NULL;
107  }
108
109
110  bool Configuration::equal_false(const std::string& str) const
111  {
112    return str=="false" || str=="False" || str=="FALSE" ||
113      str=="no" || str=="No" || str=="NO";
114  }
115
116
117  bool Configuration::equal_true(const std::string& str) const
118  {
119    return str=="true" || str=="True" || str=="TRUE" ||
120      str=="yes" || str=="Yes" || str=="YES";
121  }
122
123
124  void Configuration::load(void)
125  {
126    set_default();
127  }
128
129
130  void Configuration::load(std::istream& is)
131  {
132    assert(is.good());
133    set_default();
134
135    bool parsing_found=false;
136    bool dictionary_found=false;
137    std::string line;
138    std::string section;
139    std::string tmp;
140    while (getline(is, line)) {
141      line = ltrim(line);
142      if (line.empty() || line[0]=='#')
143        continue;
144      std::stringstream ss(line);
145      if (line[0] == '[') {
146        getline(ss, tmp, '[');
147        getline(ss, section, ']');
148        continue;
149      }
150      getline(ss, tmp, '=');
151      std::string lhs = trim(tmp);
152      getline(ss, tmp);
153      std::string rhs = trim(tmp);
154      if (rhs.empty()){
155        std::stringstream mess;
156        mess << "svndigest: invalid config file: "
157             << "line: `" << line << "' is invalid.";
158        throw std::runtime_error(mess.str());
159      }
160      if (section == "copyright-alias"){
161        std::map<std::string,Alias>::iterator iter = 
162          copyright_alias_.lower_bound(lhs);
163        if (iter!=copyright_alias_.end() && iter->first==lhs){
164          std::stringstream mess;
165          mess << "svndigest: invalid config file: "
166               << "in copright-alias section " << lhs << " defined twice.";
167          throw std::runtime_error(mess.str());
168        }
169       
170        // insert alias
171        copyright_alias_.insert(iter,std::make_pair(lhs, Alias(rhs,copyright_alias_.size())));
172      }
173      else if (section == "trac"){
174        if (lhs=="trac-root")
175          trac_root_=rhs;
176        else {
177          std::stringstream mess;
178          mess << "svndigest: invalid config file: "
179               << "in trac section" << lhs + " is invalid option.";
180          throw std::runtime_error(mess.str());
181        }
182      }
183      else if (section == "copyright") {
184        if (lhs=="missing-copyright-warning")
185          if (equal_false(rhs))
186            missing_copyright_warning_ = false;
187          else if (equal_true(rhs))
188            missing_copyright_warning_ = true;
189          else {
190            std::stringstream mess;
191            mess << "svndigest: invalid config file: "
192                 << "line: `" << line << "' is invalid.";
193            throw std::runtime_error(mess.str());
194          }
195      }
196      else if (section == "parsing-codons") {
197        if (!parsing_found) {
198          parsing_found=true;
199          // clearing the default setting
200          string2codons_.clear();
201        }
202       
203        if (codon(lhs)) {
204          std::stringstream mess;
205          mess << "svndigest: invalid config file\n"
206               << "line: `" << line << "' is invalid.\n"
207               << "clashes with previous given file name pattern: ";
208          // find previous file-name-pattern
209          for (String2Codons::const_iterator i(string2codons_.begin());
210               i!=string2codons_.end(); ++i) {
211            if (svndigest::equal(lhs.begin(), lhs.end(), 
212                                 i->first.begin(), i->first.end()) ) {
213              mess << "`" << i->first << "'";
214              break;
215            }
216          }
217          throw std::runtime_error(mess.str());
218        }
219        std::stringstream ss(rhs);
220        std::string start;
221        while (getline(ss, start, ':')) {
222          start = trim(start);
223          std::string end;
224          getline(ss, end, ';');
225          end = trim(end);
226          if (!start.empty() && !end.empty()) {
227            replace(start, "<NEWLINE>", "\n");
228            replace(end, "<NEWLINE>", "\n");
229            add_codon(lhs, start, end);
230          }
231          else if (!start.empty() || !end.empty()) {
232            std::stringstream mess;
233            mess << "svndigest: invalid config file\n"
234                 << "line: `" << line << "' is invalid.\n";
235            throw std::runtime_error(mess.str());
236          }
237        }
238      } 
239      else if (section == "file-name-dictionary") {
240        if (!dictionary_found) {
241          dictionary_found=true;
242          // clearing the default setting
243          dictionary_.clear();
244        }
245       
246        if (const std::pair<std::string, std::string>* entry=dictionary(lhs)) {
247          std::stringstream mess;
248          mess << "svndigest: invalid config file\n"
249               << "line: `" << line << "' is invalid.\n"
250               << "clashes with previous given file name pattern: "
251               << "`" << entry->first << "'";
252          throw std::runtime_error(mess.str());
253        }
254        lhs = trim(lhs);
255        rhs = trim(rhs);
256        if (!lhs.empty() && !rhs.empty()) 
257          dictionary_.push_back(std::make_pair(lhs, rhs));
258        else if (!lhs.empty() || !rhs.empty()) {
259            std::stringstream mess;
260            mess << "svndigest: invalid config file\n"
261                 << "line: `" << line << "' is invalid.\n";
262            throw std::runtime_error(mess.str());
263        }
264      } 
265    }
266  }
267
268
269  Configuration& Configuration::instance(void)
270  {
271    if (!instance_)
272      instance_ = new Configuration;
273    return *instance_;
274  }
275
276
277  bool Configuration::missing_copyright_warning(void) const
278  {
279    return missing_copyright_warning_;
280  }
281
282
283  std::string
284  Configuration::translate(const std::string& str,
285                           const std::pair<std::string, std::string>& dic) const
286  {
287    assert(svndigest::equal(str.begin(), str.end(),
288                            dic.first.begin(), dic.first.end()));
289    std::string res;
290    std::vector<std::string> vec;
291    regexp(str.begin(), str.end(), dic.first.begin(), dic.first.end(), vec);
292    for (std::string::const_iterator i(dic.second.begin()); 
293         i!=dic.second.end(); ++i) {
294      if (*i == '$') {
295        std::stringstream ss(std::string(i, dic.second.end()));
296        size_t n = 0;
297        ss >> n;
298        if (n>vec.size()){
299          std::stringstream mess;
300          mess << n;
301          throw std::runtime_error(mess.str());
302        }
303        if (n) {
304          res += vec[n-1];
305          ++i;
306          if (n>9){
307            ++i;
308            if (n>99)
309              ++i;
310          }
311        }
312        else
313          throw std::runtime_error("");
314      }
315      else
316        res += *i;
317    }
318
319    return res;
320  }
321
322
323  std::string trans_end_code(std::string str)
324  {
325    if (str.size()>0 && str[str.size()-1]=='\n')
326      return str.substr(0, str.size()-1) + std::string("<NEWLINE>");
327    return str;
328  }
329
330
331  std::string trans_beg_code(std::string str)
332  {
333    if (str.size()>0 && str[0]=='\n')
334      return std::string("<NEWLINE>") + str.substr(1); 
335    return str;
336  }
337
338
339  void Configuration::set_default(void)
340  {
341    copyright_alias_.clear();
342    missing_copyright_warning_=false;
343    trac_root_ = "";
344
345    add_codon("*.ac", "#", "\n");
346    add_codon("*.ac", "dnl", "\n");
347    add_codon("*.am", "#", "\n");
348    add_codon("*.am", "dnl", "\n");
349    add_codon("*.m4", "#", "\n");
350    add_codon("*.m4", "dnl", "\n");
351    add_codon("*.c", "//", "\n");
352    add_codon("*.c", "/*", "*/");
353    add_codon("*.cc", "//", "\n");
354    add_codon("*.cc", "/*", "*/");
355    add_codon("*.cpp", "//", "\n");
356    add_codon("*.cpp", "/*", "*/");
357    add_codon("*.cxx", "//", "\n");
358    add_codon("*.cxx", "/*", "*/");
359    add_codon("*.h", "//", "\n");
360    add_codon("*.h", "/*", "*/");
361    add_codon("*.hh", "//", "\n");
362    add_codon("*.hh", "/*", "*/");
363    add_codon("*.hpp", "//", "\n");
364    add_codon("*.hpp", "/*", "*/");
365    add_codon("*.java", "//", "\n");
366    add_codon("*.java", "/*", "*/");
367    add_codon("*.pl", "#", "\n");
368    add_codon("*.pm", "#", "\n");
369    add_codon("*.sh", "#", "\n");
370    add_codon("*config", "#", "\n");
371    add_codon("bootstrap", "#", "\n");
372    add_codon("Makefile", "#", "\n");
373    add_codon("*.tex", "%", "\n");
374    add_codon("*.m", "%", "\n");
375    add_codon("*.jsp", "<!--", "-->");
376    add_codon("*.html", "<%--", "--%>");
377    add_codon("*.xml", "<!--", "-->");
378    add_codon("*.xsl", "<!--", "-->");
379    add_codon("*.xsd", "<!--", "-->");
380    add_codon("*.xhtml", "<!--", "-->");
381    add_codon("*.shtml", "<!--", "-->");
382    add_codon("*.xml", "<!--", "-->");
383    add_codon("*.css", "<!--", "-->");
384    add_codon("*.rss", "<!--", "-->");
385    add_codon("*.sgml", "<!--", "-->");
386    add_codon("*.bat", "\nREM", "\n");
387    add_codon("*.bat", "\nrem", "\n");
388
389    dictionary_ = VectorPair(1, std::make_pair("*.in", "$1"));
390  }
391
392
393  std::string Configuration::trac_root(void) const
394  {
395    return trac_root_;
396  }
397
398
399  std::ostream& operator<<(std::ostream& os, const Configuration& conf)
400  {
401    os << "### This file configures various behaviors for svndigest\n"
402       << "### The commented-out below are intended to demonstrate how to use\n"
403       << "### this file.\n"
404       << "\n"
405       << "### Section for setting behaviour of copyright update\n"
406       << "[copyright]\n"
407       << "# if true svndigest will warn if file has no copyright statement.\n"
408       << "missing-copyright-warning = ";
409   
410    if (conf.missing_copyright_warning())
411      os << "yes\n";
412    else
413      os << "no\n";
414
415    os << "\n"
416       << "### Section for setting aliases used in copyright update\n"
417       << "[copyright-alias]\n"
418       << "# jdoe = John Doe\n";
419
420    typedef std::vector<std::pair<std::string, Alias> > vector;
421    vector vec;
422    std::back_insert_iterator<vector> back_insert_iterator(vec);
423    vec.reserve(conf.copyright_alias().size());
424    std::copy(conf.copyright_alias().begin(), conf.copyright_alias().end(),
425              back_insert_iterator);
426    // sort with respect to Alias.id
427    IdCompare id;
428    PairSecondCompare<const std::string, Alias, IdCompare> comp(id);
429    std::sort(vec.begin(),vec.end(), comp);
430             
431
432    for (vector::const_iterator i(vec.begin()); i!=vec.end(); ++i) {
433      os << i->first << " = " << i->second.name() << " \n";
434    }
435
436    os << "\n"
437       << "### Section for setting trac environment\n"
438       << "[trac]\n"
439       << "# If trac-root is set, svndigest will create anchors to "
440       << "the Trac page.\n"
441       << "# trac-root = http://trac.thep.lu.se/trac/svndigest/\n";
442    if (!conf.trac_root().empty())
443      os << "trac-root = " << conf.trac_root() << "\n";
444
445    if (!conf.dictionary_.empty()) {
446      os << "\n"
447         << "### Section for setting dictionary for file names.\n"
448         << "### Prior looking for file name pattern in section [codon],\n"
449         << "### the file name may be translated according to the rules \n"
450         << "### in this section. In default setting there is, for example,\n"
451         << "### a rule to translate `<FILENAME>.in' to `<FILENAME>'.\n"
452         << "### The format of the entries is:\n"
453         << "###    file-name-pattern = new-name\n"
454         << "### Left hand side may contain wildcards (such as '*' and '?').\n"
455         << "### Right hand side may contain \"$i\", which will be replaced \n"
456         << "### with the ith wild card in lhs string.\n"
457         << "[file-name-dictionary]\n";
458      for (size_t i=0; i<conf.dictionary_.size(); ++i)
459        os << conf.dictionary_[i].first << " = " 
460           << conf.dictionary_[i].second << "\n"; 
461    }
462    if (!conf.string2codons_.empty()) {
463      os << "\n"
464         << "### Section for setting parsing modes\n"
465         << "### The format of the entries is:\n"
466         << "###   file-name-pattern = start-code : end-code\n"
467         << "### The file-name-pattern may contain wildcards (such as '*' "
468         << "and '?').\n"
469         << "### String \"<NEWLINE>\" can be used for codons containing newline"
470         << "\n### character: '\\n'\n"
471         << "[parsing-codons]\n";
472      for (size_t i=0; i<conf.string2codons_.size(); ++i) {
473        os << conf.string2codons_[i].first << " = "; 
474        for (size_t j=0; j<conf.string2codons_[i].second.size(); ++j) {
475          if (j)
476            os << "  ;  ";
477          os << trans_beg_code(conf.string2codons_[i].second[j].first) 
478             << " : " 
479             << trans_end_code(conf.string2codons_[i].second[j].second); 
480        }
481        os << "\n";
482      }
483    }
484    return os;
485  }
486
487
488}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.