summaryrefslogtreecommitdiffabout
path: root/lib/sitecing_enflesher.ll
Side-by-side diff
Diffstat (limited to 'lib/sitecing_enflesher.ll') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/sitecing_enflesher.ll76
1 files changed, 64 insertions, 12 deletions
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
@@ -19,31 +19,21 @@ ID [A-Za-z_][A-Za-z0-9_]*
%%
^\%\%\#[^\n]+\n {
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;
}
^\%\%[^\n]+\n {
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;
}
\<\%component_basename\%\> outs << parser.component_basename; anchor_time = true;
\<\%impl\%\> outs << parser.impl; anchor_time = true;
\<\%member_functions:impl\%\> {
@@ -194,9 +184,71 @@ void sitecing_enflesher::enflesh() {
void sitecing_enflesher::anchor() {
if(!anchoraged)
return;
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:
*/