-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 |
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 | ||
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) { |
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 | ||
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,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> |
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 | } |
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 | ||
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 | |||
@@ -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 | ||
17 | namespace sitecing { | 17 | namespace 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 | } |