-rw-r--r-- | include/sitecing/sitecing_enflesher.h | 13 | ||||
-rw-r--r-- | lib/component_factory.cc | 21 | ||||
-rw-r--r-- | lib/file_factory.cc | 3 | ||||
-rw-r--r-- | lib/sitecing_enflesher.ll | 76 | ||||
-rw-r--r-- | lib/sitecing_util.cc | 4 |
5 files changed, 95 insertions, 22 deletions
diff --git a/include/sitecing/sitecing_enflesher.h b/include/sitecing/sitecing_enflesher.h index 512a358..8bc43a0 100644 --- a/include/sitecing/sitecing_enflesher.h +++ b/include/sitecing/sitecing_enflesher.h | |||
@@ -13,54 +13,67 @@ using namespace std; | |||
13 | #ifndef sitecing_enflesher_flexlexer_once | 13 | #ifndef sitecing_enflesher_flexlexer_once |
14 | #define sitecing_enflesher_flexlexer_once | 14 | #define sitecing_enflesher_flexlexer_once |
15 | #undef yyFlexLexer | 15 | #undef yyFlexLexer |
16 | #define yyFlexLexer sitecing_enflesherFlexLexer | 16 | #define yyFlexLexer sitecing_enflesherFlexLexer |
17 | #include <FlexLexer.h> | 17 | #include <FlexLexer.h> |
18 | #undef yyFlexLexerOnce | 18 | #undef yyFlexLexerOnce |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | class sitecing_parser; | 21 | class sitecing_parser; |
22 | /** | 22 | /** |
23 | * The enfleshing of the skeleton file according to the in-memory parsed | 23 | * The enfleshing of the skeleton file according to the in-memory parsed |
24 | * component source. | 24 | * component source. |
25 | */ | 25 | */ |
26 | class sitecing_enflesher : public sitecing_enflesherFlexLexer { | 26 | class sitecing_enflesher : public sitecing_enflesherFlexLexer { |
27 | public: | 27 | public: |
28 | /** | 28 | /** |
29 | * It is time to anchor output with the #line directive. | 29 | * It is time to anchor output with the #line directive. |
30 | */ | 30 | */ |
31 | bool anchor_time; | 31 | bool anchor_time; |
32 | /** | 32 | /** |
33 | * The file currently being written is supposed to have #line | 33 | * The file currently being written is supposed to have #line |
34 | * directives all around the place. | 34 | * directives all around the place. |
35 | */ | 35 | */ |
36 | bool anchoraged; | 36 | bool anchoraged; |
37 | /** | 37 | /** |
38 | * The reference to the parser object containg the parsed source. | 38 | * The reference to the parser object containg the parsed source. |
39 | */ | 39 | */ |
40 | sitecing_parser& parser; | 40 | sitecing_parser& parser; |
41 | /** | 41 | /** |
42 | * The output stream. | 42 | * The output stream. |
43 | */ | 43 | */ |
44 | ofstream outs; | 44 | ofstream outs; |
45 | /** | ||
46 | * the outs stream destination file. | ||
47 | * @see outs | ||
48 | */ | ||
49 | string outs_filename; | ||
45 | 50 | ||
46 | /** | 51 | /** |
47 | * @param p The parser object containing preparsed data. | 52 | * @param p The parser object containing preparsed data. |
48 | */ | 53 | */ |
49 | sitecing_enflesher(sitecing_parser& p) | 54 | sitecing_enflesher(sitecing_parser& p) |
50 | : parser(p), anchor_time(true) { } | 55 | : parser(p), anchor_time(true) { } |
51 | 56 | ||
52 | /** | 57 | /** |
53 | * Do the job. | 58 | * Do the job. |
54 | */ | 59 | */ |
55 | void enflesh(); | 60 | void enflesh(); |
56 | 61 | ||
57 | virtual void LexerOutput(const char *buf,int size); | 62 | virtual void LexerOutput(const char *buf,int size); |
58 | virtual int yylex(); | 63 | virtual int yylex(); |
59 | 64 | ||
60 | /** | 65 | /** |
61 | * Put a #line anchor into output. | 66 | * Put a #line anchor into output. |
62 | */ | 67 | */ |
63 | void anchor(); | 68 | void anchor(); |
69 | |||
70 | /** | ||
71 | * Close previously opened output stream, rename to the 'correct' | ||
72 | * destination filename, if needed, and open new file. | ||
73 | * @see outs | ||
74 | * @see outs_filename | ||
75 | */ | ||
76 | void outs_open(const string& nfile); | ||
64 | }; | 77 | }; |
65 | 78 | ||
66 | #endif /* __SITECING_SITECING_ENFLESHER_H */ | 79 | #endif /* __SITECING_SITECING_ENFLESHER_H */ |
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,54 +1,54 @@ | |||
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 | ||
20 | namespace sitecing { | 20 | namespace 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) { |
@@ -87,73 +87,78 @@ namespace sitecing { | |||
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); |
@@ -220,64 +225,66 @@ namespace sitecing { | |||
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 |
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 | |||
@@ -10,46 +10,47 @@ | |||
10 | #endif | 10 | #endif |
11 | 11 | ||
12 | namespace sitecing { | 12 | namespace 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,75 +1,65 @@ | |||
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> |
6 | using namespace std; | 6 | using namespace std; |
7 | #include "sitecing/sitecing_exception.h" | 7 | #include "sitecing/sitecing_exception.h" |
8 | using namespace sitecing; | 8 | using 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 | } |
@@ -168,35 +158,97 @@ ID [A-Za-z_][A-Za-z0-9_]* | |||
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 | ||
182 | void sitecing_enflesher::LexerOutput(const char *buf,int size) { | 172 | void sitecing_enflesher::LexerOutput(const char *buf,int size) { |
183 | outs.write(buf,size); | 173 | outs.write(buf,size); |
184 | } | 174 | } |
185 | 175 | ||
186 | void sitecing_enflesher::enflesh() { | 176 | void 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 | ||
194 | void sitecing_enflesher::anchor() { | 184 | void 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 | |||
191 | void 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 | |||
@@ -27,71 +27,71 @@ namespace sitecing { | |||
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) { |