summaryrefslogtreecommitdiffabout
path: root/lib
Unidiff
Diffstat (limited to 'lib') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/component_factory.cc21
-rw-r--r--lib/file_factory.cc3
-rw-r--r--lib/sitecing_enflesher.ll76
-rw-r--r--lib/sitecing_util.cc4
4 files changed, 82 insertions, 22 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,325 +1,332 @@
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 } 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) { }
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)) )
176 // TODO:TODO: linker_error 181 // TODO:TODO: linker_error
177 throw compile_error(CODEPOINT,"failed to link component",noro); 182 throw compile_error(CODEPOINT,"failed to link component",noro);
178 return; 183 return;
179 }catch(utility_no_prefix& unp) { 184 }catch(utility_no_prefix& unp) {
180 throw konforka::exception(CODEPOINT,"component is outside of component root"); 185 throw konforka::exception(CODEPOINT,"component is outside of component root");
181 }catch(utility_no_suffix& uns) { 186 }catch(utility_no_suffix& uns) {
182 } 187 }
183 // compiler targets 188 // compiler targets
184 for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) { 189 for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) {
185 try { 190 try {
186 string nos = strip_suffix(dp,cc_targets[cct]); 191 string nos = strip_suffix(dp,cc_targets[cct]);
187 string noro = strip_prefix(nos,root_intermediate); 192 string noro = strip_prefix(nos,root_intermediate);
188 string cc = root_intermediate+noro+".cc"; 193 string cc = root_intermediate+noro+".cc";
189 string o = root_intermediate+noro+".o"; 194 string o = root_intermediate+noro+".o";
190 if(access(cc.c_str(),R_OK)) 195 if(access(cc.c_str(),R_OK))
191 throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")"); 196 throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")");
192 make_path(dir_name(cc),0755); 197 make_path(dir_name(cc),0755);
193 string pwd = dir_name(root_source+noro); 198 string pwd = dir_name(root_source+noro);
194 auto_chdir dir_changer(pwd); 199 auto_chdir dir_changer(pwd);
195 file_lock lock_source(root_intermediate+noro+".lock"); 200 file_lock lock_source(root_intermediate+noro+".lock");
196 file_lock lock_cc(root_intermediate+noro+".o.lock"); 201 file_lock lock_cc(root_intermediate+noro+".o.lock");
197 int stdO = open((root_intermediate+noro+".stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); 202 int stdO = open((root_intermediate+noro+".stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
198 if(stdO<0) 203 if(stdO<0)
199 throw konforka::exception(CODEPOINT,"failed to open/create compiler stdout"); 204 throw konforka::exception(CODEPOINT,"failed to open/create compiler stdout");
200 int stdE = open((root_intermediate+noro+".stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); 205 int stdE = open((root_intermediate+noro+".stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664);
201 if(stdE<0) { 206 if(stdE<0) {
202 close(stdO); 207 close(stdO);
203 throw konforka::exception(CODEPOINT,"failed to open/create compiler's stderr"); 208 throw konforka::exception(CODEPOINT,"failed to open/create compiler's stderr");
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
300 string component_factory::get_classname(const string& component) { 307 string component_factory::get_classname(const string& component) {
301 string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname"; 308 string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname";
302 make(cn); 309 make(cn);
303 ifstream ifs(cn.c_str()); 310 ifstream ifs(cn.c_str());
304 if(!ifs.good()) 311 if(!ifs.good())
305 throw konforka::exception(CODEPOINT,"failed to access component .classname"); 312 throw konforka::exception(CODEPOINT,"failed to access component .classname");
306 ifs >> cn; 313 ifs >> cn;
307 return cn; 314 return cn;
308 } 315 }
309 316
310 void component_factory::get_ancestors(const string& component,file_list_t& rv) { 317 void component_factory::get_ancestors(const string& component,file_list_t& rv) {
311 string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors"; 318 string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors";
312 make(cn); 319 make(cn);
313 ifstream ifs(cn.c_str()); 320 ifstream ifs(cn.c_str());
314 if(!ifs.good()) 321 if(!ifs.good())
315 throw konforka::exception(CODEPOINT,"filed to access component .ancestors"); 322 throw konforka::exception(CODEPOINT,"filed to access component .ancestors");
316 rv.clear(); 323 rv.clear();
317 while(!ifs.eof()) { 324 while(!ifs.eof()) {
318 string a; 325 string a;
319 ifs >> a; 326 ifs >> a;
320 if(!a.empty()) 327 if(!a.empty())
321 rv.push_back(a); 328 rv.push_back(a);
322 } 329 }
323 } 330 }
324 331
325} 332}
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 build(dst); 42 if(!is_uptodate(dst,&deps))
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,202 +1,254 @@
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";
92 } 82 }
93 }else{ 83 }else{
94 outs << i->type << " " << i->name << ";\n"; 84 outs << i->type << " " << i->name << ";\n";
95 } 85 }
96 } 86 }
97 anchor_time = true; 87 anchor_time = true;
98} 88}
99 \<\%member_functions:decl\%\>{ 89 \<\%member_functions:decl\%\>{
100 for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) { 90 for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) {
101 (i->name.empty()?outs:outs << "virtual ") 91 (i->name.empty()?outs:outs << "virtual ")
102 << i->type << " "; 92 << i->type << " ";
103 if(i->name.empty()) { 93 if(i->name.empty()) {
104 outs << parser.class_name << "()"; 94 outs << parser.class_name << "()";
105 }else if(i->name == "~") 95 }else if(i->name == "~")
106 outs << "~" << parser.class_name << "()"; 96 outs << "~" << parser.class_name << "()";
107 else 97 else
108 outs << i->name << i->args; 98 outs << i->name << i->args;
109 outs << ";\n"; 99 outs << ";\n";
110 } 100 }
111 anchor_time = true; 101 anchor_time = true;
112} 102}
113 \<\%imports:list\%\> { 103 \<\%imports:list\%\> {
114 for(sitecing_parser::member_variables_t::const_iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { 104 for(sitecing_parser::member_variables_t::const_iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
115 if(i->bComponent) 105 if(i->bComponent)
116 outs << i->initializer << endl; 106 outs << i->initializer << endl;
117 } 107 }
118 anchor_time = true; 108 anchor_time = true;
119} 109}
120 \<\%imports:includes\%\>{ 110 \<\%imports:includes\%\>{
121 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { 111 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
122 if(i->bComponent) 112 if(i->bComponent)
123 outs << "\n#include \"" << i->initializer << ".h\"\n"; 113 outs << "\n#include \"" << i->initializer << ".h\"\n";
124 } 114 }
125 anchor_time = true; 115 anchor_time = true;
126} 116}
127 \<\%imports:import\%\>{ 117 \<\%imports:import\%\>{
128 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { 118 for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) {
129 if(!i->bComponent) 119 if(!i->bComponent)
130 continue; 120 continue;
131 if(i->bTypeOnly) 121 if(i->bTypeOnly)
132 continue; 122 continue;
133 outs << "__soc_" << i->name << "=__SCIF->ss->fetch(\"" << i->initializer << "\",__SCIF); " << i->name << "=static_cast<__type_" << i->name << "*>(__soc_" << i->name << ".ac->__the_most_derived_this());\n"; 123 outs << "__soc_" << i->name << "=__SCIF->ss->fetch(\"" << i->initializer << "\",__SCIF); " << i->name << "=static_cast<__type_" << i->name << "*>(__soc_" << i->name << ".ac->__the_most_derived_this());\n";
134 } 124 }
135 anchor_time = true; 125 anchor_time = true;
136} 126}
137 127
138 \<\%base_component\%\> { 128 \<\%base_component\%\> {
139 // TODO: 129 // TODO:
140 anchor_time = true; 130 anchor_time = true;
141} 131}
142 132
143 \<\%ancestors:includes\%\>{ 133 \<\%ancestors:includes\%\>{
144 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { 134 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
145 outs << "#include \"" << i->path << ".h\"\n"; 135 outs << "#include \"" << i->path << ".h\"\n";
146 } 136 }
147 anchor_time = true; 137 anchor_time = true;
148} 138}
149 \<\%ancestors:component_list\%\>{ 139 \<\%ancestors:component_list\%\>{
150 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { 140 for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
151 outs << i->path << "\n"; 141 outs << i->path << "\n";
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
@@ -1,279 +1,279 @@
1#ifdef USE_PCH 1#ifdef USE_PCH
2 #include "pch.h" 2 #include "pch.h"
3#else 3#else
4 #include <sys/stat.h> 4 #include <sys/stat.h>
5 #include <sys/types.h> 5 #include <sys/types.h>
6 #include <unistd.h> 6 #include <unistd.h>
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <sys/ipc.h> 8 #include <sys/ipc.h>
9 #include <sys/sem.h> 9 #include <sys/sem.h>
10 #include <errno.h> 10 #include <errno.h>
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() {
114 assert(fd>=0); 114 assert(fd>=0);
115 struct flock fl; 115 struct flock fl;
116 fl.l_type = F_WRLCK; 116 fl.l_type = F_WRLCK;
117 fl.l_whence=SEEK_SET; 117 fl.l_whence=SEEK_SET;
118 fl.l_start=fl.l_len=0; 118 fl.l_start=fl.l_len=0;
119 for(int tries=3;tries;tries--) { 119 for(int tries=3;tries;tries--) {
120 if(!fcntl(fd,F_SETLK,&fl)) 120 if(!fcntl(fd,F_SETLK,&fl))
121 return; 121 return;
122 sleep(8); 122 sleep(8);
123 } 123 }
124 throw konforka::exception(CODEPOINT,"failed to obtain file lock"); 124 throw konforka::exception(CODEPOINT,"failed to obtain file lock");
125 } 125 }
126 void file_lock::unlock() { 126 void file_lock::unlock() {
127 if(fd<0) 127 if(fd<0)
128 return; 128 return;
129 struct flock fl; 129 struct flock fl;
130 fl.l_type = F_UNLCK; 130 fl.l_type = F_UNLCK;
131 fl.l_whence=SEEK_SET; 131 fl.l_whence=SEEK_SET;
132 fl.l_start=fl.l_len=0; 132 fl.l_start=fl.l_len=0;
133 int rv = fcntl(fd,F_SETLK,&fl); 133 int rv = fcntl(fd,F_SETLK,&fl);
134 close(fd); 134 close(fd);
135 fd=-1; 135 fd=-1;
136 if(rv) 136 if(rv)
137 throw konforka::exception(CODEPOINT,"failed to release file lock"); 137 throw konforka::exception(CODEPOINT,"failed to release file lock");
138 } 138 }
139 139
140 void pid_file::set(const string& f,bool u) { 140 void pid_file::set(const string& f,bool u) {
141 ofstream of(f.c_str(),ios::trunc); 141 ofstream of(f.c_str(),ios::trunc);
142 if(!of) 142 if(!of)
143 throw konforka::exception(CODEPOINT,"failed to open file for writing pid"); 143 throw konforka::exception(CODEPOINT,"failed to open file for writing pid");
144 of << getpid() << endl; 144 of << getpid() << endl;
145 of.close(); 145 of.close();
146 file_name = f; 146 file_name = f;
147 unlink_pid = u; 147 unlink_pid = u;
148 } 148 }
149 void pid_file::unlink() { 149 void pid_file::unlink() {
150 if(!unlink_pid) 150 if(!unlink_pid)
151 return; 151 return;
152 ::unlink(file_name.c_str()); 152 ::unlink(file_name.c_str());
153 } 153 }
154 154
155 void semaphore::init() { 155 void semaphore::init() {
156 deinit(); 156 deinit();
157 semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600); 157 semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600);
158 if(semid<0) 158 if(semid<0)
159 throw konforka::exception(CODEPOINT,"failed to semget()"); 159 throw konforka::exception(CODEPOINT,"failed to semget()");
160 if(semctl(semid,0,SETVAL,1)) 160 if(semctl(semid,0,SETVAL,1))
161 throw konforka::exception(CODEPOINT,"failed to semctl()"); 161 throw konforka::exception(CODEPOINT,"failed to semctl()");
162 } 162 }
163 void semaphore::deinit() { 163 void semaphore::deinit() {
164 if(semid<0) 164 if(semid<0)
165 return; 165 return;
166 semctl(semid,0,IPC_RMID,0); 166 semctl(semid,0,IPC_RMID,0);
167 } 167 }
168 void semaphore::on() { 168 void semaphore::on() {
169 assert(semid>=0); 169 assert(semid>=0);
170 struct sembuf sb; 170 struct sembuf sb;
171 sb.sem_num=0; 171 sb.sem_num=0;
172 sb.sem_op=-1; 172 sb.sem_op=-1;
173 sb.sem_flg = SEM_UNDO; 173 sb.sem_flg = SEM_UNDO;
174 while(semop(semid,&sb,1)<0) { 174 while(semop(semid,&sb,1)<0) {
175 if(errno!=EINTR) 175 if(errno!=EINTR)
176 throw konforka::exception(CODEPOINT,"failed to semop()"); 176 throw konforka::exception(CODEPOINT,"failed to semop()");
177 } 177 }
178 } 178 }
179 void semaphore::off() { 179 void semaphore::off() {
180 assert(semid>=0); 180 assert(semid>=0);
181 struct sembuf sb; 181 struct sembuf sb;
182 sb.sem_num=0; 182 sb.sem_num=0;
183 sb.sem_op=1; 183 sb.sem_op=1;
184 sb.sem_flg = SEM_UNDO; 184 sb.sem_flg = SEM_UNDO;
185 while(semop(semid,&sb,1)<0) { 185 while(semop(semid,&sb,1)<0) {
186 if(errno!=EINTR) 186 if(errno!=EINTR)
187 throw konforka::exception(CODEPOINT,"failed to semop()"); 187 throw konforka::exception(CODEPOINT,"failed to semop()");
188 } 188 }
189 } 189 }
190 190
191 void semaphore_lock::lock() { 191 void semaphore_lock::lock() {
192 assert(sem); 192 assert(sem);
193 if(locked) 193 if(locked)
194 return; 194 return;
195 sem->on(); 195 sem->on();
196 locked = true; 196 locked = true;
197 } 197 }
198 void semaphore_lock::unlock() { 198 void semaphore_lock::unlock() {
199 if(!sem) 199 if(!sem)
200 return; 200 return;
201 if(!locked) 201 if(!locked)
202 return; 202 return;
203 sem->off(); 203 sem->off();
204 locked=false; 204 locked=false;
205 } 205 }
206 206
207 string combine_path(const string& origin,const string& relative,int opts) { 207 string combine_path(const string& origin,const string& relative,int opts) {
208 string r = normalize_path(relative,0); 208 string r = normalize_path(relative,0);
209 string rv; 209 string rv;
210 // XXX: what to do if relative is empty is a question, really. 210 // XXX: what to do if relative is empty is a question, really.
211 if(r.empty()) { 211 if(r.empty()) {
212 return normalize_path( (opts&origin_is_file)?dir_name(origin):origin ,strip_leading_slash|restrict_dotdot|strip_trailing_slash); 212 return normalize_path( (opts&origin_is_file)?dir_name(origin):origin ,strip_leading_slash|restrict_dotdot|strip_trailing_slash);
213 }else{ 213 }else{
214 if(r[0]=='/') { 214 if(r[0]=='/') {
215 r.erase(0,1); 215 r.erase(0,1);
216 }else{ 216 }else{
217 rv = normalize_path((opts&origin_is_file)?dir_name(origin):origin,restrict_dotdot|strip_trailing_slash); 217 rv = normalize_path((opts&origin_is_file)?dir_name(origin):origin,restrict_dotdot|strip_trailing_slash);
218 } 218 }
219 } 219 }
220 string::size_type lsl = rv.rfind('/'); 220 string::size_type lsl = rv.rfind('/');
221 for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) { 221 for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) {
222 assert(sl!=0); 222 assert(sl!=0);
223 if(sl==1 && r[0]=='.') { 223 if(sl==1 && r[0]=='.') {
224 // it's a "./" 224 // it's a "./"
225 r.erase(0,2); 225 r.erase(0,2);
226 }else if(sl==2 && r[0]=='.' && r[1]=='.') { 226 }else if(sl==2 && r[0]=='.' && r[1]=='.') {
227 // we have a "../" 227 // we have a "../"
228 if(lsl==string::npos) { 228 if(lsl==string::npos) {
229 if(rv.empty() && (opts&fail_beyond_root)) 229 if(rv.empty() && (opts&fail_beyond_root))
230 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path"); 230 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
231 rv.clear(); 231 rv.clear();
232 }else{ 232 }else{
233 rv.erase(lsl); 233 rv.erase(lsl);
234 lsl = rv.rfind('/'); 234 lsl = rv.rfind('/');
235 } 235 }
236 r.erase(0,3); 236 r.erase(0,3);
237 }else{ 237 }else{
238 // we have a "something/" 238 // we have a "something/"
239 lsl = rv.length(); 239 lsl = rv.length();
240 rv += '/'; 240 rv += '/';
241 rv += r.substr(0,sl); 241 rv += r.substr(0,sl);
242 r.erase(0,sl+1); 242 r.erase(0,sl+1);
243 } 243 }
244 } 244 }
245 if(r.empty()) 245 if(r.empty())
246 return rv+'/'; 246 return rv+'/';
247 if(r.length()==2 && r[0]=='.' && r[0]=='.') { 247 if(r.length()==2 && r[0]=='.' && r[0]=='.') {
248 if(lsl==string::npos) { 248 if(lsl==string::npos) {
249 if(rv.empty() & (opts&fail_beyond_root)) 249 if(rv.empty() & (opts&fail_beyond_root))
250 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path"); 250 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
251 return "/"; 251 return "/";
252 }else{ 252 }else{
253 rv.erase(lsl+1); 253 rv.erase(lsl+1);
254 return rv; 254 return rv;
255 } 255 }
256 } 256 }
257 rv += '/'; 257 rv += '/';
258 rv += r; 258 rv += r;
259 return rv; 259 return rv;
260 } 260 }
261 261
262 void auto_chdir::pushdir(const string& td,bool ap) { 262 void auto_chdir::pushdir(const string& td,bool ap) {
263 /* TODO: make use of fchdir(2) instead */ 263 /* TODO: make use of fchdir(2) instead */
264 char *tmp = getcwd(0,0); 264 char *tmp = getcwd(0,0);
265 assert(tmp); 265 assert(tmp);
266 saved_pwd = tmp; 266 saved_pwd = tmp;
267 free(tmp); 267 free(tmp);
268 autopop=ap; 268 autopop=ap;
269 if(chdir(td.c_str())) 269 if(chdir(td.c_str()))
270 throw konforka::exception(CODEPOINT,"failed to chdir()"); 270 throw konforka::exception(CODEPOINT,"failed to chdir()");
271 } 271 }
272 void auto_chdir::popdir() { 272 void auto_chdir::popdir() {
273 autopop=false; 273 autopop=false;
274 if(chdir(saved_pwd.c_str())) 274 if(chdir(saved_pwd.c_str()))
275 throw konforka::exception(CODEPOINT,"failed to chdir()"); 275 throw konforka::exception(CODEPOINT,"failed to chdir()");
276 // XXX: or should it be thrown? after all we call it from destructor... 276 // XXX: or should it be thrown? after all we call it from destructor...
277 } 277 }
278 278
279} 279}