summaryrefslogtreecommitdiffabout
path: root/lib
authorMichael Krelin <hacker@klever.net>2005-03-30 15:50:28 (UTC)
committer Michael Krelin <hacker@klever.net>2005-03-30 15:50:28 (UTC)
commit3ddbfeafde93d1aab16a710498d86eef4e787406 (patch) (unidiff)
treed53ef21cf3b2bddfeb957c98344d0be8759ed555 /lib
parent642dc685bd0a3f1526e22827a4539aa0e06aeff7 (diff)
downloadsitecing-3ddbfeafde93d1aab16a710498d86eef4e787406.zip
sitecing-3ddbfeafde93d1aab16a710498d86eef4e787406.tar.gz
sitecing-3ddbfeafde93d1aab16a710498d86eef4e787406.tar.bz2
1. preprocessor doesn't touch unchanged files anymore
2. doublechedk on whether file is up to date when making 3. changed the way preprocessor targets depend on the timestamp file 4. a bugfix in strip_suffix/strip_prefix
Diffstat (limited to 'lib') (more/less context) (show whitespace changes)
-rw-r--r--lib/component_factory.cc19
-rw-r--r--lib/file_factory.cc1
-rw-r--r--lib/sitecing_enflesher.ll76
-rw-r--r--lib/sitecing_util.cc4
4 files changed, 80 insertions, 20 deletions
diff --git a/lib/component_factory.cc b/lib/component_factory.cc
index f8666dc..b8f5a16 100644
--- a/lib/component_factory.cc
+++ b/lib/component_factory.cc
@@ -1,175 +1,180 @@
1#ifdef USE_PCH 1#ifdef USE_PCH
2 #include "pch.h" 2 #include "pch.h"
3#else 3#else
4 #include <sys/types.h> 4 #include <sys/types.h>
5 #include <sys/stat.h> 5 #include <sys/stat.h>
6 #include <unistd.h> 6 #include <unistd.h>
7 #include <sys/wait.h> 7 #include <sys/wait.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <iostream> 9 #include <iostream>
10 #include <fstream> 10 #include <fstream>
11 #include <stdexcept> 11 #include <stdexcept>
12 #include <vector> 12 #include <vector>
13 using namespace std; 13 using namespace std;
14 #include "sitecing/component_factory.h" 14 #include "sitecing/component_factory.h"
15 #include "sitecing/sitecing_util.h" 15 #include "sitecing/sitecing_util.h"
16 #include "sitecing/sitecing_parser.h" 16 #include "sitecing/sitecing_parser.h"
17 #include "sitecing/sitecing_exception.h" 17 #include "sitecing/sitecing_exception.h"
18#endif 18#endif
19 19
20namespace sitecing { 20namespace sitecing {
21 21
22 static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors" }; 22 static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors", ".pp_stamp" };
23 static const char *cc_targets[] = { ".o", ".d" }; 23 static const char *cc_targets[] = { ".o", ".d" };
24 24
25 component_factory::component_factory(configuration& c) 25 component_factory::component_factory(configuration& c)
26 : config(c), 26 : config(c),
27 root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'), 27 root_source(normalize_path(c.root_source,strip_trailing_slash)+'/'),
28 root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'), 28 root_intermediate(normalize_path(c.root_intermediate,strip_trailing_slash)+'/'),
29 root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') { 29 root_so(normalize_path(c.root_so,strip_trailing_slash)+'/') {
30 } 30 }
31 31
32 void component_factory::get_dependencies(const string& dst,file_list_t& deps) { 32 void component_factory::get_dependencies(const string& dst,file_list_t& deps) {
33 deps.clear(); 33 deps.clear();
34 string dp = normalize_path(dst,strip_trailing_slash); 34 string dp = normalize_path(dst,strip_trailing_slash);
35 // source documents 35 // source documents
36 try { // XXX: or just compare it off? 36 try { // XXX: or just compare it off?
37 string noro = strip_prefix(dp,root_source); 37 string noro = strip_prefix(dp,root_source);
38 return; 38 return;
39 }catch(utility_no_affix& una) { 39 }catch(utility_no_affix& una) {
40 } 40 }
41 // .so binaries 41 // .so binaries
42 try { 42 try {
43 string noso = strip_suffix(dp,".so"); 43 string noso = strip_suffix(dp,".so");
44 string noro = strip_prefix(noso,root_so); 44 string noro = strip_prefix(noso,root_so);
45 deps.push_back(root_intermediate+noro+".o"); 45 deps.push_back(root_intermediate+noro+".o");
46 config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps); 46 config_options *co_so_deps = config.lookup_config(noro,config_options::flag_so_deps);
47 if(co_so_deps) { 47 if(co_so_deps) {
48 for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i) 48 for(list<string>::const_iterator i=co_so_deps->so_deps.begin();i!=co_so_deps->so_deps.end();++i)
49 deps.push_back(*i); 49 deps.push_back(*i);
50 } 50 }
51 return; 51 return;
52 }catch(utility_no_prefix& unp) { 52 }catch(utility_no_prefix& unp) {
53 throw konforka::exception(CODEPOINT,"component is outside of component root"); 53 throw konforka::exception(CODEPOINT,"component is outside of component root");
54 }catch(utility_no_suffix& uns) { 54 }catch(utility_no_suffix& uns) {
55 } 55 }
56 // preprocessor targets 56 // preprocessor targets
57 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { 57 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
58 try { 58 try {
59 string nos = strip_suffix(dp,pp_targets[ppt]); 59 string nos = strip_suffix(dp,pp_targets[ppt]);
60 string noro = strip_prefix(nos,root_intermediate); 60 string noro = strip_prefix(nos,root_intermediate);
61 deps.push_back(root_source+noro); 61 deps.push_back(root_source+noro);
62 ifstream imports((root_intermediate+noro+".imports").c_str(),ios::in); 62 ifstream imports((root_intermediate+noro+".imports").c_str(),ios::in);
63 if(imports.good()) { 63 if(imports.good()) {
64 string str; 64 string str;
65 while(!imports.eof()) { 65 while(!imports.eof()) {
66 imports >> str; 66 imports >> str;
67 if(!str.empty()) 67 if(!str.empty())
68 deps.push_back(root_intermediate+str+".classname"); 68 deps.push_back(root_intermediate+str+".classname");
69 } 69 }
70 } 70 }
71 ifstream ancestors((root_intermediate+noro+".ancestors").c_str(),ios::in); 71 ifstream ancestors((root_intermediate+noro+".ancestors").c_str(),ios::in);
72 if(ancestors.good()) { 72 if(ancestors.good()) {
73 string str; 73 string str;
74 while(!ancestors.eof()) { 74 while(!ancestors.eof()) {
75 ancestors >> str; 75 ancestors >> str;
76 if(!str.empty()) 76 if(!str.empty())
77 deps.push_back(root_intermediate+str+".classname"); 77 deps.push_back(root_intermediate+str+".classname");
78 } 78 }
79 } 79 }
80 config_options *co_intermediate_deps = config.lookup_config(noro,config_options::flag_intermediate_deps); 80 config_options *co_intermediate_deps = config.lookup_config(noro,config_options::flag_intermediate_deps);
81 if(co_intermediate_deps) { 81 if(co_intermediate_deps) {
82 for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i) 82 for(list<string>::const_iterator i=co_intermediate_deps->intermediate_deps.begin();i!=co_intermediate_deps->intermediate_deps.end();++i)
83 deps.push_back(*i); 83 deps.push_back(*i);
84 } 84 }
85 return; 85 return;
86 }catch(utility_no_affix& una) { 86 }catch(utility_no_affix& una) {
87 // do nothing. must be a cpp dependency. 87 // do nothing. must be a cpp dependency.
88 } 88 }
89 } 89 }
90 // compiler targets 90 // compiler targets
91 for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) { 91 for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) {
92 try { 92 try {
93 string nos = strip_suffix(dp,cc_targets[cct]); 93 string nos = strip_suffix(dp,cc_targets[cct]);
94 string noro = strip_prefix(nos,root_intermediate); 94 string noro = strip_prefix(nos,root_intermediate);
95 deps.push_back(root_intermediate+noro+".cc"); 95 deps.push_back(root_intermediate+noro+".cc");
96 config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps); 96 config_options *co_cpp_deps = config.lookup_config(noro,config_options::flag_cpp_deps);
97 if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) { 97 if( (!co_cpp_deps) || co_cpp_deps->cpp_deps) {
98 ifstream df((root_intermediate+noro+".d").c_str(),ios::in); 98 ifstream df((root_intermediate+noro+".d").c_str(),ios::in);
99 if(df.good()) { 99 if(df.good()) {
100 string str; 100 string str;
101 while(!df.eof()) { 101 while(!df.eof()) {
102 df >> str; 102 df >> str;
103 if(str.find_first_of("\\:")==string::npos) 103 if(str.find_first_of("\\:")==string::npos)
104 deps.push_back(combine_path(config.root_source+noro,str)); 104 deps.push_back(combine_path(config.root_source+noro,str));
105 } 105 }
106 } 106 }
107 } 107 }
108 // XXX: extra deps like IntermediateDeps? 108 // XXX: extra deps like IntermediateDeps?
109 }catch(utility_no_affix& una) { 109 }catch(utility_no_affix& una) {
110 // do nothing. 110 // do nothing.
111 } 111 }
112 } 112 }
113 } 113 }
114 114
115 bool component_factory::is_uptodate(const string& dst,file_list_t *deps) { 115 bool component_factory::is_uptodate(const string& dst,file_list_t *deps) {
116 string dp = normalize_path(dst,strip_trailing_slash); 116 string dp = normalize_path(dst,strip_trailing_slash);
117 // XXX: or just compare it off, instead of throwing things around. 117 // XXX: or just compare it off, instead of throwing things around.
118 try { 118 try {
119 strip_prefix(dp,root_intermediate); 119 string noro = strip_prefix(dp,root_intermediate);
120 return file_factory::is_uptodate(dst,deps); 120 for(int ppt=0;(ppt+1)<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
121 }catch(utility_no_prefix& unp) { 121 try {
122 string nos = strip_suffix(noro,pp_targets[ppt]);
123 return file_factory::is_uptodate(root_intermediate+nos+".pp_stamp",deps);
124 }catch(utility_no_suffix& uns) { }
122 } 125 }
126 bool rv = file_factory::is_uptodate(dst,deps);
127 return rv;
128 }catch(utility_no_prefix& unp) { }
123 try { 129 try {
124 strip_prefix(dp,root_so); 130 strip_prefix(dp,root_so);
125 return file_factory::is_uptodate(dst,deps); 131 return file_factory::is_uptodate(dst,deps);
126 }catch(utility_no_prefix& unp) { 132 }catch(utility_no_prefix& unp) { }
127 }
128 return true; 133 return true;
129 } 134 }
130 135
131 void component_factory::build(const string& dst) { 136 void component_factory::build(const string& dst) {
132 string dp = normalize_path(dst,strip_trailing_slash); 137 string dp = normalize_path(dst,strip_trailing_slash);
133 // sources 138 // sources
134 try { 139 try {
135 string noro = strip_prefix(dp,root_source); 140 string noro = strip_prefix(dp,root_source);
136 // building the sources is left up to developer 141 // building the sources is left up to developer
137 return; 142 return;
138 }catch(utility_no_prefix& unp) { 143 }catch(utility_no_prefix& unp) {
139 } 144 }
140 // .so files 145 // .so files
141 try { 146 try {
142 string noso = strip_suffix(dp,".so"); 147 string noso = strip_suffix(dp,".so");
143 string noro = strip_prefix(noso,root_so); 148 string noro = strip_prefix(noso,root_so);
144 string o = root_intermediate+noro+".o"; 149 string o = root_intermediate+noro+".o";
145 if(access(o.c_str(),R_OK)) 150 if(access(o.c_str(),R_OK))
146 throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")"); 151 throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")");
147 make_path(dir_name(root_so+noro),0755); 152 make_path(dir_name(root_so+noro),0755);
148 file_lock lock_cc(root_intermediate+noro+".o.lock"); 153 file_lock lock_cc(root_intermediate+noro+".o.lock");
149 file_lock lock_so(root_so+noro+".so.lock"); 154 file_lock lock_so(root_so+noro+".so.lock");
150 int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); 155 int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
151 if(stdO<0) 156 if(stdO<0)
152 throw konforka::exception(CODEPOINT,"failed to open/create linker stdout"); 157 throw konforka::exception(CODEPOINT,"failed to open/create linker stdout");
153 int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); 158 int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
154 if(stdE<0) { 159 if(stdE<0) {
155 close(stdO); 160 close(stdO);
156 throw konforka::exception(CODEPOINT,"failed to open/create linker stderr"); 161 throw konforka::exception(CODEPOINT,"failed to open/create linker stderr");
157 } 162 }
158 list<string> args; 163 list<string> args;
159 config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags); 164 config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags);
160 if(co_ld_flags) { 165 if(co_ld_flags) {
161 args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end()); 166 args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end());
162 } 167 }
163 args.push_back("-shared"); 168 args.push_back("-shared");
164 args.push_back(o); 169 args.push_back(o);
165 file_list_t ancestors; 170 file_list_t ancestors;
166 get_ancestors(noro,ancestors); 171 get_ancestors(noro,ancestors);
167 for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) { 172 for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) {
168 string aso=root_so+*i+".so"; 173 string aso=root_so+*i+".so";
169 make(aso); 174 make(aso);
170 args.push_back(aso); 175 args.push_back(aso);
171 } 176 }
172 args.push_back("-o"); args.push_back(dp); 177 args.push_back("-o"); args.push_back(dp);
173 // TODO: "g++" configurable 178 // TODO: "g++" configurable
174 int rv = execute("g++",args,stdO,stdE); 179 int rv = execute("g++",args,stdO,stdE);
175 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) 180 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
@@ -204,96 +209,98 @@ namespace sitecing {
204 } 209 }
205 list<string> args; 210 list<string> args;
206 config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags); 211 config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags);
207 if(co_cpp_flags) { 212 if(co_cpp_flags) {
208 args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end()); 213 args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end());
209 } 214 }
210 // TODO: maybe move it to separare config option like CoreCPPFLags? 215 // TODO: maybe move it to separare config option like CoreCPPFLags?
211 args.push_back("-I"+root_intermediate); 216 args.push_back("-I"+root_intermediate);
212 args.push_back("-I"+root_source); 217 args.push_back("-I"+root_source);
213 args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d"); 218 args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d");
214 args.push_back("-c"); 219 args.push_back("-c");
215 args.push_back(cc); 220 args.push_back(cc);
216 args.push_back("-o"); args.push_back(o); 221 args.push_back("-o"); args.push_back(o);
217 // TODO: "g++" configurable 222 // TODO: "g++" configurable
218 int rv = execute("g++",args,stdO,stdE); 223 int rv = execute("g++",args,stdO,stdE);
219 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) 224 if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) )
220 throw compile_error(CODEPOINT,"failed to compile component",noro); 225 throw compile_error(CODEPOINT,"failed to compile component",noro);
221 return; 226 return;
222 }catch(utility_no_affix& una) { 227 }catch(utility_no_affix& una) {
223 // do nothing, not a compiler target 228 // do nothing, not a compiler target
224 } 229 }
225 } 230 }
226 // preprocessor targets 231 // preprocessor targets
227 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { 232 for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
228 try { 233 try {
229 string nos = strip_suffix(dp,pp_targets[ppt]); 234 string nos = strip_suffix(dp,pp_targets[ppt]);
230 string noro = strip_prefix(nos,root_intermediate); 235 string noro = strip_prefix(nos,root_intermediate);
231 string src = root_source+noro; 236 string src = root_source+noro;
232 if(access(src.c_str(),R_OK)) 237 if(access(src.c_str(),R_OK))
233 throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")"); 238 throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")");
234 make_path(dir_name(root_intermediate+noro),0755); 239 make_path(dir_name(root_intermediate+noro),0755);
235 file_lock lock(root_intermediate+noro+".lock"); 240 file_lock lock(root_intermediate+noro+".lock");
236 sitecing_parser parser(*this); 241 sitecing_parser parser(*this);
237 config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton); 242 config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton);
238 if(co_skeleton) 243 if(co_skeleton)
239 parser.skeleton = co_skeleton->skeleton; 244 parser.skeleton = co_skeleton->skeleton;
240 static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 245 static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
241 parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash); 246 parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash);
242 for(string::size_type illc = parser.class_name.find_first_not_of(id_chars);illc!=string::npos;illc=parser.class_name.find_first_not_of(id_chars,illc)) { 247 for(string::size_type illc = parser.class_name.find_first_not_of(id_chars);illc!=string::npos;illc=parser.class_name.find_first_not_of(id_chars,illc)) {
243 string::size_type lc = parser.class_name.find_first_of(id_chars,illc); 248 string::size_type lc = parser.class_name.find_first_of(id_chars,illc);
244 int n = ((lc==string::npos)?parser.class_name.length():lc)-illc; 249 int n = ((lc==string::npos)?parser.class_name.length():lc)-illc;
245 parser.class_name.replace(illc,n,n,'_'); 250 parser.class_name.replace(illc,n,n,'_');
246 } 251 }
247 parser.class_name = "_SCC_"+parser.class_name; 252 parser.class_name = "_SCC_"+parser.class_name;
248 parser.output_basename = nos; 253 parser.output_basename = nos;
249 parser.component_basename = noro; 254 parser.component_basename = noro;
250 try { 255 try {
251 parser.preprocess(src); 256 parser.preprocess(src);
257 string sf = root_intermediate+noro+".pp_stamp";
258 ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp
252 }catch(preprocessor_error& pe) { 259 }catch(preprocessor_error& pe) {
253 pe.component_name = noro; 260 pe.component_name = noro;
254 pe.see(CODEPOINT); 261 pe.see(CODEPOINT);
255 throw; 262 throw;
256 } 263 }
257 return; 264 return;
258 }catch(utility_no_affix& una) { 265 }catch(utility_no_affix& una) {
259 // must be a crap from .d file 266 // must be a crap from .d file
260 } 267 }
261 } 268 }
262 cerr << "ignoring build request for " << dp << endl; 269 cerr << "ignoring build request for " << dp << endl;
263 } 270 }
264 271
265 int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) { 272 int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) {
266 // XXX: is it right that we do stdio/stderr tricks outside of the function? 273 // XXX: is it right that we do stdio/stderr tricks outside of the function?
267 cerr << "executing: " << cmd; 274 cerr << "executing: " << cmd;
268 vector<const char*> argv(args.size()+2); 275 vector<const char*> argv(args.size()+2);
269 argv[0]=cmd.c_str(); 276 argv[0]=cmd.c_str();
270 int an = 1; 277 int an = 1;
271 for(list<string>::const_iterator i=args.begin();i!=args.end();i++) { 278 for(list<string>::const_iterator i=args.begin();i!=args.end();i++) {
272 cerr << " " << *i ; 279 cerr << " " << *i ;
273 argv[an++] = i->c_str(); 280 argv[an++] = i->c_str();
274 } 281 }
275 cerr << endl; 282 cerr << endl;
276 argv[an++]=NULL; 283 argv[an++]=NULL;
277 pid_t pid = vfork(); 284 pid_t pid = vfork();
278 if(pid==-1) { 285 if(pid==-1) {
279 close(stdo); close(stde); 286 close(stdo); close(stde);
280 throw konforka::exception(CODEPOINT,"failed to vfork()"); 287 throw konforka::exception(CODEPOINT,"failed to vfork()");
281 } 288 }
282 if(!pid) { 289 if(!pid) {
283 // child 290 // child
284 if(dup2(stdo,1)!=1) 291 if(dup2(stdo,1)!=1)
285 _exit(-1); 292 _exit(-1);
286 if(dup2(stde,2)!=2) 293 if(dup2(stde,2)!=2)
287 _exit(-1); 294 _exit(-1);
288 close(0); 295 close(0);
289 execvp(cmd.c_str(),(char**)&argv.front()); 296 execvp(cmd.c_str(),(char**)&argv.front());
290 _exit(-1); 297 _exit(-1);
291 } 298 }
292 // parent 299 // parent
293 close(stdo); close(stde); 300 close(stdo); close(stde);
294 int rv; 301 int rv;
295 if(waitpid(pid,&rv,0)<0) 302 if(waitpid(pid,&rv,0)<0)
296 throw konforka::exception(CODEPOINT,"failed to waitpid()"); 303 throw konforka::exception(CODEPOINT,"failed to waitpid()");
297 return rv; 304 return rv;
298 } 305 }
299 306
diff --git a/lib/file_factory.cc b/lib/file_factory.cc
index c6b5748..7ca7b86 100644
--- a/lib/file_factory.cc
+++ b/lib/file_factory.cc
@@ -1,55 +1,56 @@
1#ifdef USE_PCH 1#ifdef USE_PCH
2 #include "pch.h" 2 #include "pch.h"
3#else 3#else
4 #include <sys/types.h> 4 #include <sys/types.h>
5 #include <sys/stat.h> 5 #include <sys/stat.h>
6 #include <unistd.h> 6 #include <unistd.h>
7 #include <konforka/exception.h> 7 #include <konforka/exception.h>
8 using namespace std; 8 using namespace std;
9 #include "sitecing/file_factory.h" 9 #include "sitecing/file_factory.h"
10#endif 10#endif
11 11
12namespace sitecing { 12namespace sitecing {
13 13
14 bool file_factory::is_uptodate(const string& dst,file_list_t* deps) { 14 bool file_factory::is_uptodate(const string& dst,file_list_t* deps) {
15 file_list_t deplist; 15 file_list_t deplist;
16 file_list_t *fl = deps?deps:&deplist; 16 file_list_t *fl = deps?deps:&deplist;
17 get_dependencies(dst,*fl); 17 get_dependencies(dst,*fl);
18 struct stat stdst; 18 struct stat stdst;
19 if(stat(dst.c_str(),&stdst)) 19 if(stat(dst.c_str(),&stdst))
20 return false; 20 return false;
21 for(file_list_t::const_iterator i=fl->begin();i!=fl->end();i++) { 21 for(file_list_t::const_iterator i=fl->begin();i!=fl->end();i++) {
22 struct stat stdep; 22 struct stat stdep;
23 if(stat(i->c_str(),&stdep)) 23 if(stat(i->c_str(),&stdep))
24 return false; 24 return false;
25 if(stdst.st_mtime<stdep.st_mtime) 25 if(stdst.st_mtime<stdep.st_mtime)
26 return false; 26 return false;
27 if(!is_uptodate(*i)) 27 if(!is_uptodate(*i))
28 return false; 28 return false;
29 } 29 }
30 return true; 30 return true;
31 } 31 }
32 32
33 void file_factory::make(const string& dst) { 33 void file_factory::make(const string& dst) {
34 try { 34 try {
35 depth++; 35 depth++;
36 if(depth>25) 36 if(depth>25)
37 throw konforka::exception(CODEPOINT,"recursed too deeply."); 37 throw konforka::exception(CODEPOINT,"recursed too deeply.");
38 file_list_t deps; 38 file_list_t deps;
39 if(!is_uptodate(dst,&deps)) { 39 if(!is_uptodate(dst,&deps)) {
40 for(file_list_t::const_iterator i=deps.begin();i!=deps.end();i++) 40 for(file_list_t::const_iterator i=deps.begin();i!=deps.end();i++)
41 make(*i); 41 make(*i);
42 if(!is_uptodate(dst,&deps))
42 build(dst); 43 build(dst);
43 } 44 }
44 depth--; 45 depth--;
45 }catch(konforka::exception& ke) { 46 }catch(konforka::exception& ke) {
46 depth--; 47 depth--;
47 ke.see(CODEPOINT); 48 ke.see(CODEPOINT);
48 throw; 49 throw;
49 }catch(...) { 50 }catch(...) {
50 depth--; 51 depth--;
51 throw; 52 throw;
52 } 53 }
53 } 54 }
54 55
55} 56}
diff --git a/lib/sitecing_enflesher.ll b/lib/sitecing_enflesher.ll
index 5f631d7..46489c7 100644
--- a/lib/sitecing_enflesher.ll
+++ b/lib/sitecing_enflesher.ll
@@ -1,91 +1,81 @@
1%{ 1%{
2#include <iostream> 2#include <iostream>
3#include <fstream> 3#include <fstream>
4#include <cassert> 4#include <cassert>
5#include <stdexcept> 5#include <stdexcept>
6using namespace std; 6using namespace std;
7#include "sitecing/sitecing_exception.h" 7#include "sitecing/sitecing_exception.h"
8using namespace sitecing; 8using namespace sitecing;
9#define sitecing_enflesher_flexlexer_once 9#define sitecing_enflesher_flexlexer_once
10#include "sitecing/sitecing_enflesher.h" 10#include "sitecing/sitecing_enflesher.h"
11#include "sitecing/sitecing_parser.h" 11#include "sitecing/sitecing_parser.h"
12#undef yyFlexLexer 12#undef yyFlexLexer
13#define yyFlexLexer sitecing_enflesherFlexLexer 13#define yyFlexLexer sitecing_enflesherFlexLexer
14%} 14%}
15%option 8bit c++ verbose noyywrap yyclass="sitecing_enflesher" yylineno prefix="sitecing_enflesher" stack debug 15%option 8bit c++ verbose noyywrap yyclass="sitecing_enflesher" yylineno prefix="sitecing_enflesher" stack debug
16 16
17 ID[A-Za-z_][A-Za-z0-9_]* 17 ID[A-Za-z_][A-Za-z0-9_]*
18 18
19%% 19%%
20 20
21 ^\%\%\#[^\n]+\n{ 21 ^\%\%\#[^\n]+\n{
22 string line = yytext; 22 string line = yytext;
23 line.erase(0,3); 23 line.erase(0,3);
24 line.erase(line.length()-1); 24 line.erase(line.length()-1);
25 outs.flush(); 25 outs_open(parser.output_basename+line);
26 outs.close();
27 outs.clear();
28 outs.open((parser.output_basename+line).c_str(),ios::trunc);
29 if(!outs.good())
30 throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
31 anchor(); 26 anchor();
32 anchoraged = true; 27 anchoraged = true;
33} 28}
34 ^\%\%[^\n]+\n{ 29 ^\%\%[^\n]+\n{
35 string line = yytext; 30 string line = yytext;
36 line.erase(0,2); 31 line.erase(0,2);
37 line.erase(line.length()-1); 32 line.erase(line.length()-1);
38 outs.flush(); 33 outs_open(parser.output_basename+line);
39 outs.close();
40 outs.clear();
41 outs.open((parser.output_basename+line).c_str(),ios::trunc);
42 if(!outs.good())
43 throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
44 anchoraged = false; 34 anchoraged = false;
45} 35}
46 36
47 \<\%component_basename\%\>outs << parser.component_basename; anchor_time = true; 37 \<\%component_basename\%\>outs << parser.component_basename; anchor_time = true;
48 \<\%impl\%\> outs << parser.impl; anchor_time = true; 38 \<\%impl\%\> outs << parser.impl; anchor_time = true;
49 \<\%member_functions:impl\%\>{ 39 \<\%member_functions:impl\%\>{
50 for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) { 40 for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
51 outs << i->type << " " << parser.class_name << "::"; 41 outs << i->type << " " << parser.class_name << "::";
52 if(i->name.empty()) { 42 if(i->name.empty()) {
53 outs << parser.class_name << "()"; 43 outs << parser.class_name << "()";
54 bool first = true; 44 bool first = true;
55 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { 45 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
56 if(i->initializer.empty()) 46 if(i->initializer.empty())
57 continue; 47 continue;
58 if(first) { 48 if(first) {
59 outs << ":"; 49 outs << ":";
60 first=false; 50 first=false;
61 }else{ 51 }else{
62 outs << ","; 52 outs << ",";
63 } 53 }
64 if(i->bComponent) { 54 if(i->bComponent) {
65 outs << i->name << "(NULL)"; 55 outs << i->name << "(NULL)";
66 }else { 56 }else {
67 outs << i->name << "(" << i->initializer << ")"; 57 outs << i->name << "(" << i->initializer << ")";
68 } 58 }
69 } 59 }
70 }else if(i->name == "~") 60 }else if(i->name == "~")
71 outs << "~" << parser.class_name << "()"; 61 outs << "~" << parser.class_name << "()";
72 else 62 else
73 outs << i->name << i->args; 63 outs << i->name << i->args;
74 outs << "{\n" << i->body << "\n}\n"; 64 outs << "{\n" << i->body << "\n}\n";
75 } 65 }
76 anchor_time = true; 66 anchor_time = true;
77} 67}
78 \<\%class_name\%\> outs << parser.class_name; anchor_time = true; 68 \<\%class_name\%\> outs << parser.class_name; anchor_time = true;
79 \<\%baseclass_header\%\>outs << parser.base_header; anchor_time = true; 69 \<\%baseclass_header\%\>outs << parser.base_header; anchor_time = true;
80 \<\%decl\%\> outs << parser.decl; anchor_time = true; 70 \<\%decl\%\> outs << parser.decl; anchor_time = true;
81 \<\%baseclass_name\%\> outs << parser.base_class; anchor_time = true; 71 \<\%baseclass_name\%\> outs << parser.base_class; anchor_time = true;
82 \<\%member_variables:decl\%\>{ 72 \<\%member_variables:decl\%\>{
83 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { 73 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
84 if(i->bComponent) { 74 if(i->bComponent) {
85 if(i->type.empty()) { 75 if(i->type.empty()) {
86 i->type = parser.factory.get_classname(i->initializer); 76 i->type = parser.factory.get_classname(i->initializer);
87 } 77 }
88 if(i->bTypeOnly) { 78 if(i->bTypeOnly) {
89 outs << "typedef " << i->type << " " << i->name << ";\n"; 79 outs << "typedef " << i->type << " " << i->name << ";\n";
90 }else{ 80 }else{
91 outs << "typedef " << i->type << " __type_" << i->name << ";\nsitecing::so_component __soc_" << i->name << ";\n__type_" << i->name << " *" << i->name << ";\n"; 81 outs << "typedef " << i->type << " __type_" << i->name << ";\nsitecing::so_component __soc_" << i->name << ";\n__type_" << i->name << " *" << i->name << ";\n";
@@ -152,51 +142,113 @@ ID [A-Za-z_][A-Za-z0-9_]*
152 } 142 }
153 anchor_time = true; 143 anchor_time = true;
154} 144}
155 \<\%ancestors:base_clause_part\%\>{ 145 \<\%ancestors:base_clause_part\%\>{
156 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { 146 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
157 outs << ", virtual public " << parser.factory.get_classname(i->path); 147 outs << ", virtual public " << parser.factory.get_classname(i->path);
158 } 148 }
159} 149}
160 \<\%ancestors:typedefs\%\> { 150 \<\%ancestors:typedefs\%\> {
161 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { 151 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
162 outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n"; 152 outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n";
163 } 153 }
164 anchor_time = true; 154 anchor_time = true;
165} 155}
166 \<\%ancestors:import\%\> { 156 \<\%ancestors:import\%\> {
167 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { 157 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
168 outs << i->name << "::__do_imports();\n"; 158 outs << i->name << "::__do_imports();\n";
169 } 159 }
170 anchor_time = true; 160 anchor_time = true;
171} 161}
172 162
173 \n { 163 \n {
174 if(anchor_time) 164 if(anchor_time)
175 anchor(); 165 anchor();
176 ECHO; 166 ECHO;
177} 167}
178 . ECHO; 168 . ECHO;
179 169
180%% 170%%
181 171
182void sitecing_enflesher::LexerOutput(const char *buf,int size) { 172void sitecing_enflesher::LexerOutput(const char *buf,int size) {
183 outs.write(buf,size); 173 outs.write(buf,size);
184} 174}
185 175
186void sitecing_enflesher::enflesh() { 176void sitecing_enflesher::enflesh() {
187 ifstream ifs(parser.skeleton.c_str()); 177 ifstream ifs(parser.skeleton.c_str());
188 if(!ifs.good()) 178 if(!ifs.good())
189 throw preprocessor_error(CODEPOINT,"failed to open skeleton file"); 179 throw preprocessor_error(CODEPOINT,"failed to open skeleton file");
190 switch_streams(&ifs,NULL); 180 switch_streams(&ifs,NULL);
191 yylex(); 181 yylex();
192} 182}
193 183
194void sitecing_enflesher::anchor() { 184void sitecing_enflesher::anchor() {
195 if(!anchoraged) 185 if(!anchoraged)
196 return; 186 return;
197 outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n"; 187 outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n";
198 anchor_time = false; 188 anchor_time = false;
199} 189}
190
191void sitecing_enflesher::outs_open(const string& nfile) {
192 if(!outs_filename.empty()) {
193 outs.flush();
194 outs.close();
195 outs.clear();
196 /*
197 * compare source and destination files.
198 *
199 * one can also keep a hash for the old one and compute one for the
200 * output while writing, but I'm not sure if it's any better. Surely a
201 * bit less accurate, unless we're going to compare it in case of
202 * difference, anyway.
203 */
204 bool overwrite = false;
205 struct stat st_s, st_d;
206 string fn_s = outs_filename+".new";
207 string fn_d = outs_filename;
208 if(stat(fn_d.c_str(),&st_d)) {
209 overwrite = true;
210 }else{
211 if(stat(fn_s.c_str(),&st_s))
212 throw preprocessor_error(CODEPOINT,"failed to stat() supposedly created file");
213 if(st_s.st_size!=st_d.st_size) {
214 overwrite = true;
215 }else{
216 ifstream i_s(fn_s.c_str(),ios::in);
217 if(!i_s)
218 throw preprocessor_error(CODEPOINT,"failed to open supposedly created file");
219 ifstream i_d(fn_d.c_str(),ios::in);
220 if(!i_d)
221 throw preprocessor_error(CODEPOINT,"failed to open the old preprocessed source");
222 off_t remaining = st_s.st_size;
223 char t1[2048];
224 char t2[sizeof(t1)];
225 while(remaining) {
226 int rb = remaining;
227 if(rb>sizeof(t1))
228 rb = sizeof(t1);
229 if(i_s.read(t1,rb).gcount()!=rb)
230 throw preprocessor_error(CODEPOINT,"error reading just created file");
231 if(i_d.read(t2,rb).gcount()!=rb)
232 throw preprocessor_error(CODEPOINT,"error reading the old preprocessed source");
233 if(memcmp(t1,t2,rb)) {
234 overwrite = true;
235 break;
236 }
237 remaining -= rb;
238 }
239 }
240 }
241 if(overwrite) {
242 cerr << "renaming '" << fn_s << "'" << endl;
243 if(rename(fn_s.c_str(),fn_d.c_str()))
244 throw preprocessor_error(CODEPOINT,"failed to rename() generated output");
245 }
246 }
247 outs_filename = nfile;
248 outs.open((nfile+".new").c_str(),ios::trunc);
249 if(!outs.good())
250 throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
251}
200/* 252/*
201 * vim:set ft=lex: 253 * vim:set ft=lex:
202 */ 254 */
diff --git a/lib/sitecing_util.cc b/lib/sitecing_util.cc
index 5466b28..f892a60 100644
--- a/lib/sitecing_util.cc
+++ b/lib/sitecing_util.cc
@@ -11,103 +11,103 @@
11 #include <iostream> 11 #include <iostream>
12 #include <fstream> 12 #include <fstream>
13 #include <cassert> 13 #include <cassert>
14 #include "sitecing/sitecing_util.h" 14 #include "sitecing/sitecing_util.h"
15#endif 15#endif
16 16
17namespace sitecing { 17namespace sitecing {
18 18
19 /* 19 /*
20 * XXX: all of these utilities could be sheerly optimized. 20 * XXX: all of these utilities could be sheerly optimized.
21 */ 21 */
22 22
23 string normalize_path(const string& path,int opts) { 23 string normalize_path(const string& path,int opts) {
24 const char *s = path.c_str(); 24 const char *s = path.c_str();
25 string rv; 25 string rv;
26 string::size_type notslash = 0; 26 string::size_type notslash = 0;
27 if( (*s)=='.' && s[1]=='/' ) 27 if( (*s)=='.' && s[1]=='/' )
28 s+=2; 28 s+=2;
29 if(opts&strip_leading_slash) 29 if(opts&strip_leading_slash)
30 for(;(*s) && (*s)=='/';s++); 30 for(;(*s) && (*s)=='/';s++);
31 for(;*s;s++) { 31 for(;*s;s++) {
32 if( (*s)=='/' ) { 32 if( (*s)=='/' ) {
33 if(s[1]=='/') 33 if(s[1]=='/')
34 continue; 34 continue;
35 if(s[1]=='.' && s[2]=='/') { 35 if(s[1]=='.' && s[2]=='/') {
36 s+=2; 36 s+=2;
37 continue; 37 continue;
38 } 38 }
39 } 39 }
40 if(opts&restrict_dotdot) { 40 if(opts&restrict_dotdot) {
41 if( 41 if(
42 ( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' )// "^../" 42 ( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' )// "^../"
43 || ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)" 43 || ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)"
44 ) 44 )
45 throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered"); 45 throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered");
46 } 46 }
47 rv += *s; 47 rv += *s;
48 if( (*s) != '/' ) 48 if( (*s) != '/' )
49 notslash=rv.length(); 49 notslash=rv.length();
50 } 50 }
51 if(!(opts&strip_trailing_slash)) 51 if(!(opts&strip_trailing_slash))
52 notslash++; 52 notslash++;
53 if(notslash<rv.length()) 53 if(notslash<rv.length())
54 rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash 54 rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash
55 return rv; 55 return rv;
56 } 56 }
57 57
58 string strip_prefix(const string& str,const string& prefix) { 58 string strip_prefix(const string& str,const string& prefix) {
59 if(str.compare(0,prefix.length(),prefix)) 59 if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix))
60 throw utility_no_prefix(CODEPOINT,"no such prefix"); 60 throw utility_no_prefix(CODEPOINT,"no such prefix");
61 return str.substr(prefix.length()); 61 return str.substr(prefix.length());
62 } 62 }
63 63
64 string strip_suffix(const string& str,const string& suffix) { 64 string strip_suffix(const string& str,const string& suffix) {
65 if(str.compare(str.length()-suffix.length(),suffix.length(),suffix)) 65 if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix))
66 throw utility_no_suffix(CODEPOINT,"no such suffix"); 66 throw utility_no_suffix(CODEPOINT,"no such suffix");
67 return str.substr(0,str.length()-suffix.length()); 67 return str.substr(0,str.length()-suffix.length());
68 } 68 }
69 69
70 string dir_name(const string& filename) { 70 string dir_name(const string& filename) {
71 string::size_type sl = filename.find_last_of('/'); 71 string::size_type sl = filename.find_last_of('/');
72 if(sl==string::npos) 72 if(sl==string::npos)
73 return ""; // no slashes -- no dir. 73 return ""; // no slashes -- no dir.
74 string::size_type nosl = filename.find_last_not_of('/',sl); 74 string::size_type nosl = filename.find_last_not_of('/',sl);
75 if(nosl==string::npos) 75 if(nosl==string::npos)
76 return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir? 76 return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir?
77 return filename.substr(0,nosl+1); 77 return filename.substr(0,nosl+1);
78 } 78 }
79 79
80 void make_path(const string& path,mode_t mode) { 80 void make_path(const string& path,mode_t mode) {
81 struct stat st; 81 struct stat st;
82 for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) { 82 for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) {
83 if(!sl) 83 if(!sl)
84 continue; 84 continue;
85 string p = path.substr(0,sl); 85 string p = path.substr(0,sl);
86 if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) { 86 if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) {
87 if(mkdir(p.c_str(),mode)) 87 if(mkdir(p.c_str(),mode))
88 throw konforka::exception(CODEPOINT,"failed to mkdir()"); 88 throw konforka::exception(CODEPOINT,"failed to mkdir()");
89 } 89 }
90 } 90 }
91 if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) { 91 if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) {
92 if(mkdir(path.c_str(),mode)) 92 if(mkdir(path.c_str(),mode))
93 throw konforka::exception(CODEPOINT,"failed to mkdir()"); 93 throw konforka::exception(CODEPOINT,"failed to mkdir()");
94 } 94 }
95 } 95 }
96 96
97 void file_lock::lock(const string& f) { 97 void file_lock::lock(const string& f) {
98 unlock(); 98 unlock();
99 fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR); 99 fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
100 if(fd<0) 100 if(fd<0)
101 throw konforka::exception(CODEPOINT,"failed to open/create lockfile"); 101 throw konforka::exception(CODEPOINT,"failed to open/create lockfile");
102 try { 102 try {
103 lock(); 103 lock();
104 }catch(konforka::exception& ke) { 104 }catch(konforka::exception& ke) {
105 ke.see(CODEPOINT); 105 ke.see(CODEPOINT);
106 close(fd); fd=-1; 106 close(fd); fd=-1;
107 throw; 107 throw;
108 }catch(...) { 108 }catch(...) {
109 close(fd); fd=-1; 109 close(fd); fd=-1;
110 throw; 110 throw;
111 } 111 }
112 } 112 }
113 void file_lock::lock() { 113 void file_lock::lock() {