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