# # # patch "Makefile.am" # from [9718304152afdf5dbc4eb43e4cc6ccd1e40c6570] # to [c4b17e8b3bd2bf201e4df2a6b1c509aac9fcd188] # # patch "txt2c.cc" # from [eedf5a5a6ba149eba89310b53ee08223983de6e9] # to [810cb63bef54dd15ec21812c34032343b73c668c] # ============================================================ --- Makefile.am 9718304152afdf5dbc4eb43e4cc6ccd1e40c6570 +++ Makefile.am c4b17e8b3bd2bf201e4df2a6b1c509aac9fcd188 @@ -565,35 +565,33 @@ CLEANFILES = $(BUILT_SOURCES) $(CLEAN_SO CLEANFILES = $(BUILT_SOURCES) $(CLEAN_SOURCES) $(EPS_FIGURES) $(CLEAN_POFILES) -# override compiler for txt2c +# automake provides no nice way to build a helper program to execute +# on the build machine, so we need our own rule. almost all the +# standard flags variables are inappropriate. txt2c$(EXEEXT): txt2c.cc - $(CXX_FOR_BUILD) $(CXXFLAGS) -o $@ $< + $(CXX_FOR_BUILD) $(CXXFLAGS) -o $@ $^ -# FIXME: should use stamp files. -%.cc: %.sql txt2c$(EXEEXT) - ./txt2c $(TXT2CFLAGS) --no-static $< $(*F) >address@hidden - cmp -s address@hidden $@ || mv -f address@hidden $@ - rm -f address@hidden +# files generated using txt2c +std_hooks.cc: std_hooks.lua txt2c$(EXEEXT) + ./txt2c std_hooks $< $@ -%.cc: %.lua txt2c$(EXEEXT) - ./txt2c $(TXT2CFLAGS) --no-static $< $(*F) >address@hidden - cmp -s address@hidden $@ || mv -f address@hidden $@ - rm -f address@hidden +testlib.cc: testlib.lua txt2c$(EXEEXT) + ./txt2c testlib $< $@ -%.cc: %.txt txt2c$(EXEEXT) - ./txt2c $(TXT2CFLAGS) --no-static $< $(*F) >address@hidden - cmp -s address@hidden $@ || mv -f address@hidden $@ - rm -f address@hidden +schema.cc: schema.sql txt2c$(EXEEXT) + ./txt2c schema $< $@ +package_revision.cc: package_revision.txt txt2c$(EXEEXT) + ./txt2c --strip-trailing package_revision $< $@ + +package_full_revision.cc: 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.cc. -TXT2CFLAGS = -package_revision.cc : 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. @@ -628,8 +626,8 @@ package_full_revision_raw.txt: .PHONY: package_full_revision_raw.txt package_full_revision_raw.txt: REAL_BLDDIR=$$PWD/$(top_builddir); \ - (cd $(srcdir) && $$REAL_BLDDIR/mtn --root=. automate get_revision) 2>/dev/null >$@ \ - || (cd $(srcdir) && mtn --root=. automate get_revision) 2>/dev/null >$@ \ + (cd $(srcdir) && $$REAL_BLDDIR/mtn --root=. automate get_current_revision) 2>/dev/null >$@ \ + || (cd $(srcdir) && mtn --root=. automate get_current_revision) 2>/dev/null >$@ \ || rm -f $@ # See above comment -- the file this depends on may or may not exist. # This file, however, must always exist, so that 'make dist' can ============================================================ --- 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: