]> git.tdb.fi Git - builder.git/blob - source/config.cpp
Fix compile errors on 64-bit systems
[builder.git] / source / config.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2006-2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <cstdlib>
9 #include <msp/core/except.h>
10 #include <msp/fs/stat.h>
11 #include <msp/fs/utils.h>
12 #include <msp/io/except.h>
13 #include <msp/io/file.h>
14 #include <msp/io/print.h>
15 #include <msp/time/utils.h>
16 #include "builder.h"
17 #include "config.h"
18 #include "sourcepackage.h"
19
20 using namespace std;
21 using namespace Msp;
22
23 Config::Config(SourcePackage &p):
24         package(p),
25         freeze_mtime(false)
26 { }
27
28 void Config::add_option(const string &n, const string &v, const string &d)
29 {
30         options.insert(OptionMap::value_type(n, Option(n, v, d)));
31 }
32
33 const Config::Option &Config::get_option(const string &name) const
34 {
35         OptionMap::const_iterator i=options.find(name);
36         if(i==options.end())
37                 throw KeyError("Unknown option", name);
38
39         return i->second;
40 }
41
42 bool Config::is_option(const string &name) const
43 {
44         return options.count(name);
45 }
46
47 void Config::select_last_profile()
48 {
49         try
50         {
51                 IO::BufferedFile in((package.get_source()/".profile").str());
52                 string profile;
53                 in.getline(profile);
54                 set_option("profile", profile);
55         }
56         catch(const IO::FileNotFound &)
57         { }
58
59         freeze_mtime=true;
60         package.get_builder().apply_profile_template(*this, get_option("profile").value);
61         freeze_mtime=false;
62
63         load();
64 }
65
66 void Config::select_profile(const string &profile)
67 {
68         set_option("profile", profile);
69
70         if(!package.get_builder().get_dry_run())
71         {
72                 IO::BufferedFile out((package.get_source()/".profile").str(), IO::M_WRITE);
73                 IO::print(out, "%s\n", profile);
74         }
75
76         freeze_mtime=true;
77         package.get_builder().apply_profile_template(*this, profile);
78         freeze_mtime=false;
79
80         load();
81 }
82
83 bool Config::update(const StringMap &opts)
84 {
85         bool changed=false;
86         for(StringMap::const_iterator i=opts.begin(); i!=opts.end(); ++i)
87         {
88                 if(set_option(i->first, i->second) && i->first!="profile")
89                         changed=true;
90         }
91
92         if(changed && !freeze_mtime)
93                 mtime=Time::now();
94
95         return changed;
96 }
97
98 void Config::finish()
99 {
100         for(unsigned n=0; n<20; ++n)
101         {
102                 bool changed=false;
103                 for(OptionMap::iterator i=options.begin(); i!=options.end(); ++i)
104                 {
105                         Option &opt=i->second;
106                         string::size_type dollar=0;
107                         while((dollar=opt.value.find('$', dollar))!=string::npos)
108                         {
109                                 string::size_type end;
110                                 string var;
111                                 if(opt.value[dollar+1]=='{')
112                                 {
113                                         end=opt.value.find('}', dollar+2);
114                                         if(end==string::npos)
115                                                 throw Exception("Unterminated variable reference");
116                                         var=opt.value.substr(dollar+2, end-dollar-2);
117                                         ++end;
118                                 }
119                                 else
120                                 {
121                                         for(end=dollar+1; (isalnum(opt.value[end]) && opt.value[end]!='_'); ++end) ;
122                                         var=opt.value.substr(dollar+1, end-dollar-1);
123                                 }
124
125                                 string value;
126                                 if(is_option(var))
127                                         value=get_option(var).value;
128                                 else if(var=="arch")
129                                         value=package.get_builder().get_current_arch().get_name();
130                                 else if(const char *ptr=getenv(var.c_str()))
131                                         value=ptr;
132
133                                 opt.value.replace(dollar, end-dollar, value);
134
135                                 dollar+=value.size();
136                                 changed=true;
137                         }
138                 }
139
140                 if(!changed)
141                         break;
142         }
143 }
144
145 void Config::save() const
146 {
147         FS::Path fn=package.get_source()/".options";
148
149         OptionMap::const_iterator i=options.find("profile");
150         if(i!=options.end())
151                 fn=package.get_source()/(".options."+i->second.value);
152
153         IO::BufferedFile out(fn.str(), IO::M_WRITE);
154
155         for(i=options.begin(); i!=options.end(); ++i)
156                 IO::print(out, "option \"%s\" \"%s\";\n", i->second.name, i->second.value);
157 }
158
159 bool Config::set_option(const string &opt, const string &val)
160 {
161         bool result=false;
162
163         OptionMap::iterator i=options.find(opt);
164         if(i!=options.end())
165         {
166                 if(i->second.value!=val)
167                         result=true;
168                 i->second.value=val;
169         }
170
171         return result;
172 }
173
174 void Config::load()
175 {
176         FS::Path fn=package.get_source()/(".options."+get_option("profile").value);
177
178         try
179         {
180                 IO::BufferedFile in(fn.str());
181
182                 mtime=Time::TimeStamp::from_unixtime(FS::stat(fn).st_mtime);
183
184                 DataFile::Parser parser(in, fn.str());
185                 Loader loader(*this);
186                 loader.load(parser);
187         }
188         catch(const IO::FileNotFound &)
189         { }
190 }
191
192
193 Config::Option::Option(const string &n, const string &v, const string &d):
194         name(n),
195         defv(v),
196         descr(d),
197         value(v)
198 { }
199
200
201 Config::Loader::Loader(Config &c):
202         conf(c)
203 {
204         add("option", &Loader::option);
205 }
206
207 void Config::Loader::option(const string &n, const string &v)
208 {
209         conf.set_option(n, v);
210 }