summaryrefslogtreecommitdiffabout
Side-by-side diff
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
@@ -42,6 +42,11 @@ class sitecing_enflesher : public sitecing_enflesherFlexLexer {
* The output stream.
*/
ofstream outs;
+ /**
+ * the outs stream destination file.
+ * @see outs
+ */
+ string outs_filename;
/**
* @param p The parser object containing preparsed data.
@@ -61,6 +66,14 @@ class sitecing_enflesher : public sitecing_enflesherFlexLexer {
* Put a #line anchor into output.
*/
void anchor();
+
+ /**
+ * Close previously opened output stream, rename to the 'correct'
+ * destination filename, if needed, and open new file.
+ * @see outs
+ * @see outs_filename
+ */
+ void outs_open(const string& nfile);
};
#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
@@ -19,7 +19,7 @@
namespace sitecing {
- static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors" };
+ static const char *pp_targets[] = { ".cc", ".h", ".imports", ".classname", ".baseclassname", ".ancestors", ".pp_stamp" };
static const char *cc_targets[] = { ".o", ".d" };
component_factory::component_factory(configuration& c)
@@ -116,15 +116,20 @@ namespace sitecing {
string dp = normalize_path(dst,strip_trailing_slash);
// XXX: or just compare it off, instead of throwing things around.
try {
- strip_prefix(dp,root_intermediate);
- return file_factory::is_uptodate(dst,deps);
- }catch(utility_no_prefix& unp) {
- }
+ string noro = strip_prefix(dp,root_intermediate);
+ for(int ppt=0;(ppt+1)<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) {
+ try {
+ string nos = strip_suffix(noro,pp_targets[ppt]);
+ return file_factory::is_uptodate(root_intermediate+nos+".pp_stamp",deps);
+ }catch(utility_no_suffix& uns) { }
+ }
+ bool rv = file_factory::is_uptodate(dst,deps);
+ return rv;
+ }catch(utility_no_prefix& unp) { }
try {
strip_prefix(dp,root_so);
return file_factory::is_uptodate(dst,deps);
- }catch(utility_no_prefix& unp) {
- }
+ }catch(utility_no_prefix& unp) { }
return true;
}
@@ -249,6 +254,8 @@ namespace sitecing {
parser.component_basename = noro;
try {
parser.preprocess(src);
+ string sf = root_intermediate+noro+".pp_stamp";
+ ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp
}catch(preprocessor_error& pe) {
pe.component_name = noro;
pe.see(CODEPOINT);
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
@@ -39,7 +39,8 @@ namespace sitecing {
if(!is_uptodate(dst,&deps)) {
for(file_list_t::const_iterator i=deps.begin();i!=deps.end();i++)
make(*i);
- build(dst);
+ if(!is_uptodate(dst,&deps))
+ build(dst);
}
depth--;
}catch(konforka::exception& ke) {
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
@@ -22,12 +22,7 @@ ID [A-Za-z_][A-Za-z0-9_]*
string line = yytext;
line.erase(0,3);
line.erase(line.length()-1);
- outs.flush();
- outs.close();
- outs.clear();
- outs.open((parser.output_basename+line).c_str(),ios::trunc);
- if(!outs.good())
- throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+ outs_open(parser.output_basename+line);
anchor();
anchoraged = true;
}
@@ -35,12 +30,7 @@ ID [A-Za-z_][A-Za-z0-9_]*
string line = yytext;
line.erase(0,2);
line.erase(line.length()-1);
- outs.flush();
- outs.close();
- outs.clear();
- outs.open((parser.output_basename+line).c_str(),ios::trunc);
- if(!outs.good())
- throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+ outs_open(parser.output_basename+line);
anchoraged = false;
}
@@ -197,6 +187,68 @@ void sitecing_enflesher::anchor() {
outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n";
anchor_time = false;
}
+
+void sitecing_enflesher::outs_open(const string& nfile) {
+ if(!outs_filename.empty()) {
+ outs.flush();
+ outs.close();
+ outs.clear();
+ /*
+ * compare source and destination files.
+ *
+ * one can also keep a hash for the old one and compute one for the
+ * output while writing, but I'm not sure if it's any better. Surely a
+ * bit less accurate, unless we're going to compare it in case of
+ * difference, anyway.
+ */
+ bool overwrite = false;
+ struct stat st_s, st_d;
+ string fn_s = outs_filename+".new";
+ string fn_d = outs_filename;
+ if(stat(fn_d.c_str(),&st_d)) {
+ overwrite = true;
+ }else{
+ if(stat(fn_s.c_str(),&st_s))
+ throw preprocessor_error(CODEPOINT,"failed to stat() supposedly created file");
+ if(st_s.st_size!=st_d.st_size) {
+ overwrite = true;
+ }else{
+ ifstream i_s(fn_s.c_str(),ios::in);
+ if(!i_s)
+ throw preprocessor_error(CODEPOINT,"failed to open supposedly created file");
+ ifstream i_d(fn_d.c_str(),ios::in);
+ if(!i_d)
+ throw preprocessor_error(CODEPOINT,"failed to open the old preprocessed source");
+ off_t remaining = st_s.st_size;
+ char t1[2048];
+ char t2[sizeof(t1)];
+ while(remaining) {
+ int rb = remaining;
+ if(rb>sizeof(t1))
+ rb = sizeof(t1);
+ if(i_s.read(t1,rb).gcount()!=rb)
+ throw preprocessor_error(CODEPOINT,"error reading just created file");
+ if(i_d.read(t2,rb).gcount()!=rb)
+ throw preprocessor_error(CODEPOINT,"error reading the old preprocessed source");
+ if(memcmp(t1,t2,rb)) {
+ overwrite = true;
+ break;
+ }
+ remaining -= rb;
+ }
+ }
+ }
+ if(overwrite) {
+ cerr << "renaming '" << fn_s << "'" << endl;
+ if(rename(fn_s.c_str(),fn_d.c_str()))
+ throw preprocessor_error(CODEPOINT,"failed to rename() generated output");
+ }
+ }
+ outs_filename = nfile;
+ outs.open((nfile+".new").c_str(),ios::trunc);
+ if(!outs.good())
+ throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
+}
/*
* vim:set ft=lex:
*/
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
@@ -56,13 +56,13 @@ namespace sitecing {
}
string strip_prefix(const string& str,const string& prefix) {
- if(str.compare(0,prefix.length(),prefix))
+ if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix))
throw utility_no_prefix(CODEPOINT,"no such prefix");
return str.substr(prefix.length());
}
string strip_suffix(const string& str,const string& suffix) {
- if(str.compare(str.length()-suffix.length(),suffix.length(),suffix))
+ if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix))
throw utility_no_suffix(CODEPOINT,"no such suffix");
return str.substr(0,str.length()-suffix.length());
}