--- /dev/null
+#include <msp/fs/utils.h>
+#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
+#include "builtingenerator.h"
+
+using namespace std;
+using namespace Msp;
+
+BuiltinGenerator::BuiltinGenerator(IO::Base &o):
+ out(o)
+{
+ out.write("#include <msp/datafile/builtinsource.h>\n\n");
+}
+
+void BuiltinGenerator::begin(const std::string &ns)
+{
+ if(!namespc.empty() || !filenames.empty())
+ throw logic_error("BuiltinGenerator::begin");
+
+ if(!ns.empty())
+ {
+ namespc = split(ns, "::");
+ for(vector<string>::const_iterator i=namespc.begin(); i!=namespc.end(); ++i)
+ out.write(format("namespace %s {\n", *i));
+ }
+}
+
+void BuiltinGenerator::add_file(const std::string &fn)
+{
+ IO::BufferedFile in(fn);
+
+ string base_fn = FS::basename(fn);
+ filenames.push_back(base_fn);
+
+ out.write(format("\nconst char %s_data[] =\n", mangle_filename(base_fn)));
+ string line;
+ while(!in.eof())
+ {
+ char buf[19];
+ unsigned len = in.read(buf, (79-line.size())/4);
+ line += c_escape(string(buf, len));
+ if(line.size()>=76 || in.eof())
+ {
+ out.write(format(" \"%s\"", line));
+ line.clear();
+ if(in.eof())
+ out.put(';');
+ out.put('\n');
+ }
+ }
+}
+
+void BuiltinGenerator::end(const string &module_name)
+{
+ out.write(format("\nvoid init_%s(DataFile::BuiltinSource &source)\n{\n", module_name));
+ for(vector<string>::const_iterator i=filenames.begin(); i!=filenames.end(); ++i)
+ out.write(format(" source.add_object(\"%s\", %s_data);\n", *i, mangle_filename(*i)));
+ out.write("}\n");
+
+ if(!namespc.empty())
+ {
+ out.put('\n');
+ for(vector<string>::const_iterator i=namespc.begin(); i!=namespc.end(); ++i)
+ out.write(format("} // namespace %s\n", *i));
+
+ namespc.clear();
+ filenames.clear();
+ }
+}
+
+string BuiltinGenerator::mangle_filename(const string &fn)
+{
+ string mangled = fn;
+ for(string::iterator i=mangled.begin(); i!=mangled.end(); ++i)
+ if(!isalnum(*i))
+ *i = '_';
+ return mangled;
+}