source: trunk/lib/Configuration.cc @ 519

Last change on this file since 519 was 519, checked in by Jari Häkkinen, 13 years ago

trac moved to new location.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.8 KB
Line 
1// $Id: Configuration.cc 519 2007-12-23 20:14:50Z jari $
2
3/*
4  Copyright (C) 2007 Peter Johansson
5
6  This file is part of svndigest, http://trac.thep.lu.se/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+1, 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/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.