--- /dev/null
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <msp/core/getopt.h>
+#include <msp/parser/loader.h>
+#include <msp/parser/parser.h>
+
+using namespace std;
+using namespace Msp;
+
+class ShoppingList
+{
+public:
+ ShoppingList(int, char **);
+ void print(ostream &);
+private:
+ class InventoryLoader: public Parser::Loader
+ {
+ public:
+ InventoryLoader(ShoppingList &);
+ private:
+ ShoppingList &sl;
+
+ void track(unsigned, unsigned);
+ };
+
+ class LayoutLoader: public Parser::Loader
+ {
+ public:
+ LayoutLoader(ShoppingList &);
+ private:
+ ShoppingList &sl;
+
+ void track(unsigned);
+ };
+
+ typedef map<unsigned, unsigned> TrackMap;
+
+ TrackMap inventory;
+ TrackMap layout;
+
+ void load_inventory(const string &);
+ void load_layout(const string &);
+};
+
+int main(int argc, char **argv)
+{
+ ShoppingList sl(argc, argv);
+ sl.print(cout);
+ return 0;
+}
+
+ShoppingList::ShoppingList(int argc, char **argv)
+{
+ string inv_fn="inventory";
+ GetOpt getopt;
+ getopt.add_option('i', "inventory", inv_fn, GetOpt::REQUIRED_ARG);
+ getopt(argc,argv);
+
+ load_inventory(inv_fn);
+ load_layout(getopt.get_args().front());
+}
+
+void ShoppingList::load_inventory(const string &fn)
+{
+ ifstream in(fn.c_str());
+ Parser::Parser parser(in, fn);
+ InventoryLoader il(*this);
+ il.load(parser);
+}
+
+void ShoppingList::load_layout(const string &fn)
+{
+ ifstream in(fn.c_str());
+ Parser::Parser parser(in, fn);
+ LayoutLoader ll(*this);
+ ll.load(parser);
+}
+
+void ShoppingList::print(ostream &out)
+{
+ out<<"// Need to get:\n";
+ for(TrackMap::iterator i=layout.begin(); i!=layout.end(); ++i)
+ {
+ TrackMap::iterator j=inventory.find(i->first);
+ if(j!=inventory.end())
+ {
+ if(j->second<i->second)
+ out<<"track "<<i->first<<' '<<i->second-j->second<<";\n";
+ }
+ else
+ out<<"track "<<i->first<<' '<<i->second<<";\n";
+ }
+
+ out<<"// Pre-existing:\n";
+ for(TrackMap::iterator i=layout.begin(); i!=layout.end(); ++i)
+ {
+ TrackMap::iterator j=inventory.find(i->first);
+ if(j!=inventory.end())
+ out<<"track "<<i->first<<' '<<min(i->second,j->second)<<";\n";
+ }
+
+ out<<"// Unused:\n";
+ for(TrackMap::iterator i=inventory.begin(); i!=inventory.end(); ++i)
+ {
+ TrackMap::iterator j=layout.find(i->first);
+ if(j!=layout.end())
+ {
+ if(j->second<i->second)
+ out<<"track "<<i->first<<' '<<i->second-j->second<<";\n";
+ }
+ else
+ out<<"track "<<i->first<<' '<<i->second<<";\n";
+ }
+}
+
+ShoppingList::InventoryLoader::InventoryLoader(ShoppingList &s):
+ sl(s)
+{
+ add("track", &InventoryLoader::track);
+}
+
+void ShoppingList::InventoryLoader::track(unsigned part, unsigned count)
+{
+ sl.inventory[part]+=count;
+}
+
+ShoppingList::LayoutLoader::LayoutLoader(ShoppingList &s):
+ sl(s)
+{
+ add("track", &LayoutLoader::track);
+ add("base");
+}
+
+void ShoppingList::LayoutLoader::track(unsigned part)
+{
+ ++sl.layout[part];
+}