# # # patch "Makefile.am" # from [9dac63927ac2719b0877c0b452f7f583e74b905c] # to [eb0b1b7425384ec86766e26825a9dde0783c8553] # # patch "txt2c.cc" # from [eedf5a5a6ba149eba89310b53ee08223983de6e9] # to [810cb63bef54dd15ec21812c34032343b73c668c] # ============================================================ --- Makefile.am 9dac63927ac2719b0877c0b452f7f583e74b905c +++ Makefile.am eb0b1b7425384ec86766e26825a9dde0783c8553 @@ -686,35 +686,27 @@ CLEANFILES = $(BUILT_SOURCES) $(CLEAN_SO CLEANFILES = $(BUILT_SOURCES) $(CLEAN_SOURCES) $(EPS_FIGURES) -txt2c: txt2c.cc - $(CXX) $(CXXFLAGS) -o $@ $< - chmod 0755 address@hidden(EXEEXT) +# files generated using txt2c +std_hooks.c: std_hooks.lua txt2c$(EXEEXT) + ./txt2c std_hooks $< $@ -# FIXME: should use stamp files. -%.c: %.sql txt2c - ./txt2c $(TXT2CFLAGS) --no-static $< $(*F) >address@hidden - cmp -s address@hidden $@ || mv -f address@hidden $@ - rm -f address@hidden +testlib.c: testlib.lua txt2c$(EXEEXT) + ./txt2c testlib $< $@ -%.c: %.lua txt2c - ./txt2c $(TXT2CFLAGS) --no-static $< $(*F) >address@hidden - cmp -s address@hidden $@ || mv -f address@hidden $@ - rm -f address@hidden +schema.c: schema.sql txt2c$(EXEEXT) + ./txt2c schema $< $@ -%.c: %.txt txt2c - ./txt2c $(TXT2CFLAGS) --no-static $< $(*F) >address@hidden - cmp -s address@hidden $@ || mv -f address@hidden $@ - rm -f address@hidden +package_revision.c: package_revision.txt txt2c$(EXEEXT) + ./txt2c --strip-trailing package_revision $< $@ +package_full_revision.c: package_full_revision.txt txt2c$(EXEEXT) + ./txt2c package_full_revision $< $@ + + # Support for scripts %: util/% cp $< $@ -# This construct causes --strip-trailing to be applied only when -# generating package_revision.c. -TXT2CFLAGS = -package_revision.c : TXT2CFLAGS = --strip-trailing - # This is phony, so that we always try to rebuild it. If it succeeds # in calculating changes, it produces its target; otherwise, its # target does not exist. ============================================================ --- txt2c.cc eedf5a5a6ba149eba89310b53ee08223983de6e9 +++ txt2c.cc 810cb63bef54dd15ec21812c34032343b73c668c @@ -1,83 +1,190 @@ #include #include +#include #include -#include -#include +#include // for strerror +#include // for rename +#include // for errno + +using std::back_inserter; using std::cerr; -using std::cout; -using std::ifstream; +using std::copy; +using std::filebuf; +using std::ios; +using std::istreambuf_iterator; +using std::ostream; +using std::ostringstream; +using std::ofstream; +using std::strerror; using std::string; -using std::strerror; -int main(int argc, char **argv) +struct ioerror { - if (argc < 3 || argc > 5) + int errcode; + string fname; + string operation; + + ioerror(char const * f, char const * op) + : errcode(errno), fname(f), operation(op) + {} + ioerror(string const & f, char const * op) + : errcode(errno), fname(f), operation(op) + {} +}; + +ostream & +operator<<(ostream & s, ioerror const & e) +{ + s << e.fname << ": " + << e.operation << " failed: " + << strerror(errno) << '\n'; + return s; +} + +static void +generate_code(string & result, + char const * fname, + char const * arrayname, + bool static_array, + bool strip_trailing) +{ + string text; + + { + filebuf fin; + if (!fin.open(fname, ios::in)) + throw ioerror(fname, "open"); + copy(istreambuf_iterator(&fin), istreambuf_iterator(), + back_inserter(text)); + } + if (strip_trailing) { - cerr << "usage: " << argv[0] - << " [--strip-trailing] [--no-static] \n"; - return 1; + int last = text.find_last_not_of(" \t\n"); + text.erase(last + 1); } + ostringstream os; + + os << "// DO NOT EDIT\n" + << "// this file is automatically generated from " << fname << ",\n" + << "// any changes you make will be destroyed when it is regenerated\n" + << "\n\n"; + + if (static_array) + os << "static "; + else + // some versions of g++ object to constants marked 'extern' and defined + // at the same time (i.e. constants declared with both 'extern' and an + // initializer). to shut them up, first declare the constant 'extern', + // then define it without 'extern'. + os << "extern char const " << arrayname << "_constant[];\n"; + + os << "char const " << arrayname << "_constant[" + << (text.size() + 1) << "] = {\n"; + + for (unsigned int i = 0; i < text.size(); ++i) + { + if (i == 0) os << '\t'; + else if (i % 14 == 0) os << "\n\t"; + os << static_cast(text[i]) << ", "; + } + os << "0\n};\n"; + + result = os.str(); +} + +static bool +compare_contents(char const *fname, string const & text) +{ + filebuf fin; + if (!fin.open(fname, ios::in)) + { + if (errno != ENOENT) + throw ioerror(fname, "open"); + return false; + } + + istreambuf_iterator fp(&fin), fend; + string::const_iterator tp(text.begin()), tend(text.end()); + + // cannot use std::equal() because it does not check that the + // sequences are the same length + while (fp != fend && tp != tend) + { + if (*fp != *tp) + return false; + fp++; + tp++; + } + + return fp == fend && tp == tend; +} + +static void +atomic_update_if_changed(char const *ofname, string const & text) +{ + if (compare_contents(ofname, text)) + return; + + string tfname(ofname); + tfname += "T"; + + { + ofstream fout(tfname.c_str()); + if (!fout) + throw ioerror(tfname, "open"); + + fout.write(text.data(), text.size()); + if (!fout.flush()) + throw ioerror(tfname, "write"); + } + + if (rename(tfname.c_str(), ofname)) + throw ioerror(ofname, "rename"); +} + +int +main(int argc, char **argv) +{ bool do_strip_trailing = false; - bool do_static = true; + bool do_static = false; + int i = 1; - if (string(argv[i]) == "--strip-trailing") + if (i < argc && string(argv[i]) == "--strip-trailing") { do_strip_trailing = true; i++; } - if (string(argv[i]) == "--no-static") + if (i < argc && string(argv[i]) == "--static") { - do_static = false; + do_static = true; i++; } - char const * fname = argv[i++]; - char const * arr = argv[i++]; - - ifstream fin(fname); - if (!fin) + if (argc - i != 3) { - int e = errno; - cerr << "could not open " << fname << " for reading: " - << strerror(e) << '\n'; + cerr << "usage: " << argv[0] + << (" [--strip-trailing] [--static]" + " \n"); return 1; } - char c; - string dat; - while(fin.get(c)) - dat += c; + char const * arr = argv[i++]; + char const * ifname = argv[i++]; + char const * ofname = argv[i]; - if (do_strip_trailing) + try { - int last = dat.find_last_not_of(" \t\n"); - dat.erase(last + 1); + string text; + generate_code(text, ifname, arr, do_static, do_strip_trailing); + atomic_update_if_changed(ofname, text); } - - cout << "// DO NOT EDIT\n" - << "// this file is automatically generated from " << fname << ",\n" - << "// any changes you make will be destroyed when it is regenerated\n" - << "\n\n"; - - if (do_static) - cout << "static "; - else - // some versions of g++ object to constants marked 'extern' and defined - // at the same time (i.e. constants declared with both 'extern' and an - // initializer). to shut them up, first declare the constant 'extern', - // then define it without 'extern'. - cout << "extern char const " << arr << "_constant[];\n"; - - cout << "char const " << arr << "_constant[" << (dat.size() + 1) << "] = {\n"; - - for (unsigned int i = 0; i < dat.size(); ++i) + catch (ioerror const & e) { - if (i == 0) cout << '\t'; - else if (i % 14 == 0) cout << "\n\t"; - cout << static_cast(dat[i]) << ", "; + cerr << e; + return 1; } - cout << "0\n};\n"; + return 0; } // Local Variables: