-rw-r--r-- | lib/sitecing_enflesher.ll | 76 |
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: */ |