[Avida-SVN] r1956 - in development/source: analyze cpu main platform targets/avida targets/avida-s targets/avida-viewer targets/viewer-text tools

brysonda at myxo.css.msu.edu brysonda at myxo.css.msu.edu
Fri Aug 17 12:00:30 PDT 2007


Author: brysonda
Date: 2007-08-17 15:00:30 -0400 (Fri, 17 Aug 2007)
New Revision: 1956

Modified:
   development/source/analyze/cAnalyze.cc
   development/source/cpu/cHardwareManager.cc
   development/source/cpu/cInstSet.cc
   development/source/cpu/cInstSet.h
   development/source/main/avida.cc
   development/source/main/avida.h
   development/source/main/cAvidaConfig.cc
   development/source/main/cAvidaConfig.h
   development/source/main/cEnvironment.cc
   development/source/main/cPopulation.cc
   development/source/main/cWorld.cc
   development/source/platform/PlatformExpert.cc
   development/source/targets/avida-s/main.cc
   development/source/targets/avida-viewer/viewer.cc
   development/source/targets/avida/primitive.cc
   development/source/targets/viewer-text/viewer-text.cc
   development/source/tools/cInitFile.cc
   development/source/tools/cInitFile.h
   development/source/tools/tHashTable.h
Log:
- Move avida.h/cc into a namespace (called Avida)
- Move command line argument processing from cAvidaConfig into Avida::
- Add a new check to verify that all command line '-set's are used, and if not report the settings as unrecognized and exit.
- Add a wholesale Set method to cAvidaConfig (takes a tDictionary<cString> reference, and consumes applicable settings)
- Add a new configuration type (custom format) to cAvidaConfig.  These configuration types simply collect lines that start with the specified keyword(s) into a cStringList that can then be processed using whatever custom logic is desired.  Note that these entries cannot be set from the command line right now.
- Add new INST_SET_NEW (the _NEW is temporary) custom group to cAvidaConfig for handling new style instruction set declarations inside of the main configuration file
- Change the behavior of cInitFile's #!include directive to accept a name after the argument.  If present, this directives value can be changed from the command line using the -def argument
- Implement more robust error reporting from cInitFile.  All errors and warnings that occur are collected into an internal tList that can be accessed for reporting to the console (or GUI)


Modified: development/source/analyze/cAnalyze.cc
===================================================================
--- development/source/analyze/cAnalyze.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/analyze/cAnalyze.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -143,6 +143,9 @@
   
   cInitFile analyze_file(filename);
   if (!analyze_file.WasOpened()) {
+    tConstListIterator<cString> err_it(analyze_file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     cerr << "Warning: Cannot load file: \"" << filename << "\"." << endl
     << "...creating it..." << endl;
     ofstream fp(filename);
@@ -206,6 +209,9 @@
   
   cInitFile input_file(filename);
   if (!input_file.WasOpened()) {
+    tConstListIterator<cString> err_it(input_file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     cerr << "Error: Cannot load file: \"" << filename << "\"." << endl;
     if (exit_on_error) exit(1);
   }
@@ -245,6 +251,9 @@
   
   cInitFile input_file(filename);
   if (!input_file.WasOpened()) {
+    tConstListIterator<cString> err_it(input_file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     cerr << "Error: Cannot load file: \"" << filename << "\"." << endl;
     if (exit_on_error) exit(1);
   }
@@ -335,6 +344,9 @@
     
     cInitFile input_file(filename);
     if (!input_file.WasOpened()) {
+      tConstListIterator<cString> err_it(input_file.GetErrors());
+      const cString* errstr = NULL;
+      while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
       cerr << "Error: Cannot load file: \"" << filename << "\"." << endl;
       if (exit_on_error) exit(1);
     }
@@ -943,6 +955,9 @@
   
   cInitFile input_file(filename);
   if (!input_file.WasOpened()) {
+    tConstListIterator<cString> err_it(input_file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     cerr << "Error: Cannot load file: \"" << filename << "\"." << endl;
     if (exit_on_error) exit(1);
   }

Modified: development/source/cpu/cHardwareManager.cc
===================================================================
--- development/source/cpu/cHardwareManager.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/cpu/cHardwareManager.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -75,7 +75,7 @@
   
   
   if (m_world->GetConfig().INST_SET_FORMAT.Get()) {
-    m_inst_set->LoadFromFile(filename);
+    m_inst_set->LoadFromConfig();
   } else {
     m_inst_set->LoadFromLegacyFile(filename);
   }

Modified: development/source/cpu/cInstSet.cc
===================================================================
--- development/source/cpu/cInstSet.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/cpu/cInstSet.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -122,6 +122,30 @@
 
 void cInstSet::LoadFromFile(const cString& filename)
 {
+  cInitFile file(filename);
+  if (!file.WasOpened()) {
+    tConstListIterator<cString> err_it(file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) m_world->GetDriver().RaiseException(*errstr);
+    m_world->GetDriver().RaiseFatalException(1, cString("Unable to load instruction set '") + filename + "'.");
+  }
+   
+  cStringList sl;
+  for (int line_id = 0; line_id < file.GetNumLines(); line_id++) {
+    sl.PushRear(file.GetLine(line_id));
+  }
+  
+  LoadWithStringList(sl);
+}
+
+
+void cInstSet::LoadFromConfig()
+{
+  LoadWithStringList(m_world->GetConfig().INST_SET_NEW.Get());
+}
+
+void cInstSet::LoadWithStringList(const cStringList& sl)
+{
   cArgSchema schema;
   
   // Integer
@@ -135,18 +159,17 @@
   schema.AddEntry("prob_fail", 0, 0.0);
   
   
-  cInitFile file(filename);
-  if (!file.WasOpened()) {
-    m_world->GetDriver().RaiseFatalException(1, cString("Unable to load instruction set '") + filename + "'.");
-  }
-  
   tList<cString> errors;
   bool success = true;
-  for (int line_id = 0; line_id < file.GetNumLines(); line_id++) {
-    cString cur_line = file.GetLine(line_id);
+  for (int line_id = 0; line_id < sl.GetSize(); line_id++) {
+    cString cur_line = sl.GetLine(line_id);
     
+    // Look for the INST keyword at the beginning of each line, and ignore if not found.
+    cString inst_name = cur_line.PopWord();
+    if (inst_name != "INST") continue;
+    
     // Lookup the instruction name in the library
-    cString inst_name = cur_line.PopWord();
+    inst_name = cur_line.PopWord();
     int fun_id = m_inst_lib->GetIndex(inst_name);
     if (fun_id == -1) {
       // Oh oh!  Didn't find an instruction!
@@ -243,6 +266,9 @@
   cInitFile file(filename);
   
   if (file.WasOpened() == false) {
+    tConstListIterator<cString> err_it(file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) m_world->GetDriver().RaiseException(*errstr);
     m_world->GetDriver().RaiseFatalException(1, cString("Could not open instruction set '") + filename + "'.");
   }
   

Modified: development/source/cpu/cInstSet.h
===================================================================
--- development/source/cpu/cInstSet.h	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/cpu/cInstSet.h	2007-08-17 19:00:30 UTC (rev 1956)
@@ -55,6 +55,7 @@
  **/
 
 class cAvidaContext;
+class cStringList;
 class cWorld;
 
 class cInstSet
@@ -76,6 +77,9 @@
   
   tArray<int> m_lib_nopmod_map;
   tArray<int> m_mutation_chart;     // ID's represented by redundancy values.
+  
+  
+  void LoadWithStringList(const cStringList& sl);
 
   cInstSet(); // @not_implemented
 
@@ -128,6 +132,7 @@
   cInstruction GetInstDefault() const { return m_inst_lib->GetInstDefault(); }
   cInstruction GetInstError() const { return m_inst_lib->GetInstError(); }
   
+  void LoadFromConfig();
   void LoadFromFile(const cString& filename);
   void LoadFromLegacyFile(const cString& filename);
 };

Modified: development/source/main/avida.cc
===================================================================
--- development/source/main/avida.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/avida.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -24,9 +24,14 @@
 
 #include "avida.h"
 
+#include "defs.h"
+#include "cActionLibrary.h"
+#include "cAvidaConfig.h"
+#include "cDriverManager.h"
 #include "cString.h"
-#include "defs.h"
+#include "tDictionary.h"
 
+
 #ifdef REVISION_SUPPORT
 #include "revision.h"
 #endif
@@ -37,7 +42,9 @@
 
 using namespace std;
 
-cString getAvidaVersion()
+namespace Avida {
+
+cString GetVersion()
 {
   cString version("Avida ");
   version += VERSION;
@@ -81,11 +88,11 @@
   return version;
 }
 
-void printVersionBanner()
+void PrintVersionBanner()
 {
   // output copyright message
 
-  cout << getAvidaVersion() << endl << endl;
+  cout << GetVersion() << endl << endl;
   cout << "----------------------------------------------------------------------" << endl;
   cout << "by Charles Ofria" << endl << endl;
 
@@ -112,8 +119,167 @@
   cout << "----------------------------------------------------------------------" << endl << endl;
 }
 
-void ExitAvida(int exit_code)
+
+void ProcessCmdLineArgs(int argc, char* argv[], cAvidaConfig* cfg)
 {
+  int arg_num = 1;              // Argument number being looked at.
+  
+  // Load all of the args into string objects for ease of access.
+  cString* args = new cString[argc];
+  for (int i = 0; i < argc; i++) args[i] = argv[i];
+  
+  cString config_filename = "avida.cfg";
+  bool crash_if_not_found = false;
+  tDictionary<cString> sets;
+  tDictionary<cString> defs;
+  
+  bool flag_analyze = false;
+  bool flag_interactive = false;
+  bool flag_load = false;         cString val_load;
+  bool flag_review = false;
+  bool flag_verbosity = false;    int val_verbosity;
+  bool flag_seed = false;         int val_seed = 0;
+  
+  // Then scan through and process the rest of the args.
+  while (arg_num < argc) {
+    cString cur_arg = args[arg_num];
+    
+    // Test against the possible inputs.
+    
+    // Print out a list of all possibel actions (was events).
+    if (cur_arg == "-e" || cur_arg == "-events" || cur_arg == "-actions") {
+      cout << endl << "Supported Actions:" << endl;
+      cout << cDriverManager::GetActionLibrary()->DescribeAll() << endl;
+      exit(0);
+    }
+    
+    // Review configuration options, listing those non-default.
+    else if (cur_arg == "-review" || cur_arg == "-r") {
+      flag_review = true;
+    }
+    
+    else if (cur_arg == "--help" || cur_arg == "-help" || cur_arg == "-h") {
+      cout << "Options:"<<endl
+      << "  -a[nalyze]            Process analyze.cfg instead of normal "
+      << "run." << endl
+      << "  -c[onfig] <filename>  Set config file to be <filename>"<<endl
+      << "  -def <name> <value>   Define config include variables" << endl
+      << "  -e; -actions          Print a list of all known actions"<< endl
+      << "  -h[elp]               Help on options (this listing)"<<endl
+      << "  -i[nteractive]        Run analyze mode interactively" << endl
+      << "  -l[oad] <filename>    Load a clone file" << endl
+      << "  -r[eview]             Review avida.cfg settings." << endl
+      << "  -s[eed] <value>       Set random seed to <value>" << endl
+      << "  -set <name> <value>   Override values in avida.cfg" << endl
+      << "  -v[ersion]            Prints the version number" << endl
+      << "  -v0 -v1 -v2 -v3 -v4   Set output verbosity to 0..4" << endl
+      << endl;
+      
+      exit(0);
+    }
+    else if (cur_arg == "-seed" || cur_arg == "-s") {
+      if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
+        cerr << "Error: Must include a number as the random seed!" << endl;
+        exit(0);
+      } else {
+        arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+        val_seed = cur_arg.AsInt();
+      }
+      flag_seed = true;
+    } else if (cur_arg == "-analyze" || cur_arg == "-a") {
+      flag_analyze = true;
+    } else if (cur_arg == "-interactive" || cur_arg == "-i") {
+      flag_interactive = true;
+    } else if (cur_arg == "-load" || cur_arg == "-l") {
+      if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
+        cerr << "Error: Must include a filename to load from." << endl;
+        exit(0);
+      } else {
+        arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+        val_load = cur_arg;
+      }
+      flag_load = true;
+    } else if (cur_arg == "-version" || cur_arg == "-v") {
+      // We've already showed version info, so just quit.
+      exit(0);
+    } else if (cur_arg.Substring(0, 2) == "-v") {
+      val_verbosity = cur_arg.Substring(2, cur_arg.GetSize() - 2).AsInt();
+      flag_verbosity = true;
+    } else if (cur_arg == "-set") {
+      if (arg_num + 1 == argc || arg_num + 2 == argc) {
+        cerr << "'-set' option must be followed by name and value" << endl;
+        exit(0);
+      }
+      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+      cString name(cur_arg);
+      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+      cString value(cur_arg);
+      sets.Add(name, value);
+    } else if (cur_arg == "-def") {
+      if (arg_num + 1 == argc || arg_num + 2 == argc) {
+        cerr << "'-def' option must be followed by name and value" << endl;
+        exit(0);
+      }
+      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+      cString name(cur_arg);
+      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+      cString value(cur_arg);
+      defs.Add(name, value);
+    } else if (cur_arg == "-c" || cur_arg == "-config") {
+      if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
+        cerr << "Error: Filename for configuration must be specified." << endl;
+        exit(0);
+      }
+      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+      config_filename = cur_arg;
+      crash_if_not_found = true;
+    } else {
+      cerr << "Error: Unknown Option '" << args[arg_num] << "'" << endl
+      << "Type: \"" << args[0] << " -h\" for a full option list." << endl;
+      exit(0);
+    }
+    
+    arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
+  }
+  
+  delete [] args;
+
+  // Load configuration file
+  cfg->Load(config_filename, defs, crash_if_not_found);
+  
+
+  // Process Command Line Flags
+  if (flag_analyze) if (cfg->ANALYZE_MODE.Get() < 1) cfg->ANALYZE_MODE.Set(1);
+  if (flag_interactive) if (cfg->ANALYZE_MODE.Get() < 2) cfg->ANALYZE_MODE.Set(2);
+  if (flag_load) cfg->CLONE_FILE.Set(val_load);
+  if (flag_seed) cfg->RANDOM_SEED.Set(val_seed);
+  if (flag_verbosity) cfg->VERBOSITY.Set(val_verbosity);
+  
+  cfg->Set(sets); // Process all command line -set statements
+  
+  if (sets.GetSize()) {
+    tList<cString> keys;
+    sets.GetKeys(keys);
+    cString* keystr = NULL;
+    while ((keystr = keys.Pop())) {
+      cerr << "Error: Unrecognized command line configuration setting '" << *keystr << "'." << endl;
+    }
+    exit(1);
+  }
+  
+  
+  if (flag_review) {
+    cfg->PrintReview();
+    exit(0);
+  }  
+  
+}
+
+
+void Exit(int exit_code)
+{
   signal(SIGINT, SIG_IGN);          // Ignore all future interupts.
   exit(exit_code);
 }
+
+};

Modified: development/source/main/avida.h
===================================================================
--- development/source/main/avida.h	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/avida.h	2007-08-17 19:00:30 UTC (rev 1956)
@@ -26,14 +26,19 @@
 #ifndef avida_h
 #define avida_h
 
+class cAvidaConfig;
 class cString;
 
-cString getAvidaVersion();
-void printVersionBanner();
 
-/**
- * This function properly shuts down the Avida program.
- **/
-void ExitAvida(int exit_code);
+namespace Avida
+{
+  cString GetVersion();
+  void PrintVersionBanner();
+  
+  void ProcessCmdLineArgs(int argc, char* argv[], cAvidaConfig* cfg);
 
+  //! This function properly shuts down the Avida program.
+  void Exit(int exit_code);
+};
+
 #endif

Modified: development/source/main/cAvidaConfig.cc
===================================================================
--- development/source/main/cAvidaConfig.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/cAvidaConfig.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -33,10 +33,12 @@
 #include "cStringIterator.h"
 #include "tDictionary.h"
 
+cMutex cAvidaConfig::global_list_mutex;
 tList<cAvidaConfig::cBaseConfigGroup> cAvidaConfig::global_group_list;
+tList<cAvidaConfig::cBaseConfigCustomFormat> cAvidaConfig::global_format_list;
 
-cAvidaConfig::cBaseConfigEntry::cBaseConfigEntry(const cString & _name,
-  const cString & _type, const cString & _def, const cString & _desc)
+cAvidaConfig::cBaseConfigEntry::cBaseConfigEntry(const cString& _name,
+  const cString& _type, const cString& _def, const cString& _desc)
 : config_name(_name)
 , type(_type)
 , default_value(_def)
@@ -65,9 +67,12 @@
   cInitFile init_file(filename, mappings);
   
   if (!init_file.WasOpened()) {
+    tConstListIterator<cString> err_it(init_file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     if (crash_if_not_found) {
       // exit the program if the requested configuration file is not found
-      cerr << "Warning: Unable to find file '" << filename 
+      cerr << "Error: Unable to find file '" << filename 
            << "'.  Ending the program." << endl;
       exit(-1);
     } else {
@@ -86,13 +91,13 @@
   
 
   // Loop through all groups, then all entrys, and try to load each one.
-  tListIterator<cBaseConfigGroup> group_it(group_list);
-  cBaseConfigGroup * cur_group;
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
+  cBaseConfigGroup* cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     
     // Loop through entries for this group...
     tListIterator<cBaseConfigEntry> entry_it(cur_group->GetEntryList());
-    cBaseConfigEntry * cur_entry;
+    cBaseConfigEntry* cur_entry;
     while ((cur_entry = entry_it.Next()) != NULL) {
       const cString keyword = cur_entry->GetName();
       const cString default_val = cur_entry->GetDefault();
@@ -100,12 +105,42 @@
     }
   }
   
+  
+  // Build dictionary of custom format entries
+  tDictionary<cBaseConfigFormatEntry*> entry_dict;
+  
+  tListIterator<cBaseConfigCustomFormat> format_it(m_format_list);
+  cBaseConfigCustomFormat* cur_format;
+  while ((cur_format = format_it.Next())) {
+    tListIterator<cBaseConfigFormatEntry> entry_it(cur_format->GetEntryList());
+    cBaseConfigFormatEntry* cur_entry;
+    while ((cur_entry = entry_it.Next())) entry_dict.Add(cur_entry->GetName(), cur_entry);
+  }
+  
+  
+  // Pass over the file again, checking for custom format entries
+  for (int line_id = 0; line_id < init_file.GetNumLines(); line_id++) {
+    cString cur_line = init_file.GetLine(line_id);
+    cString keyword = cur_line.PopWord();
+    
+    cBaseConfigFormatEntry* cur_entry;
+    if (entry_dict.Find(keyword, cur_entry)) {
+      cur_entry->LoadString(cur_line);
+      init_file.MarkLineUsed(line_id);
+    }
+  }
+  
   init_file.WarnUnused();
+
+  // Print out the collected warnings and messages
+  tConstListIterator<cString> err_it(init_file.GetErrors());
+  const cString* errstr = NULL;
+  while ((errstr = err_it.Next())) cerr << "Warning: " << *errstr << endl;
 }
 
 /* Routine to create an avida configuration file from internal default values */
 
-void cAvidaConfig::Print(const cString & filename)
+void cAvidaConfig::Print(const cString& filename)
 {
   ofstream fp(filename);
   
@@ -120,7 +155,7 @@
   
   // Loop through the groups, and print out all of the variables.
   
-  tListIterator<cBaseConfigGroup> group_it(group_list);
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
   cBaseConfigGroup * cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     // Print out the group name...
@@ -175,9 +210,9 @@
 
 void cAvidaConfig::Status()
 {
-  cout << "Config contains " << group_list.GetSize() << " groups." << endl;
+  cout << "Config contains " << m_group_list.GetSize() << " groups." << endl;
   
-  tListIterator<cBaseConfigGroup> group_it(group_list);
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
   cBaseConfigGroup * cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     cout << "Group \"" << cur_group->GetName()
@@ -191,7 +226,7 @@
   cout << endl << "Non-Default Settings: " << endl << endl;
 
   // Loop through all possible groups.
-  tListIterator<cBaseConfigGroup> group_it(group_list);
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
   cBaseConfigGroup * cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     // Loop through entries for this group...
@@ -234,7 +269,7 @@
 
   // Loop through all of the groups, printing the classes representing that
   // group followed by the classes representing the individual settings.
-  tListIterator<cBaseConfigGroup> group_it(group_list);
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
   cBaseConfigGroup * cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     fp << "/**********************************************" << endl;
@@ -265,9 +300,9 @@
     tListIterator<cBaseConfigEntry> entry_it(cur_group->GetEntryList());
     cBaseConfigEntry * cur_entry;
     while ((cur_entry = entry_it.Next()) != NULL) {
-      const cString & cur_name = cur_entry->GetName();
-      const cString & cur_default = cur_entry->GetDefault();
-      const cString & cur_type = cur_entry->GetType();
+      const cString& cur_name = cur_entry->GetName();
+      const cString& cur_default = cur_entry->GetDefault();
+      const cString& cur_type = cur_entry->GetType();
       cStringList cur_desc(cur_entry->GetDesc(), '\n');
       fp << "// Entry: " << cur_name << endl;
       fp << "// Description: ";
@@ -281,7 +316,7 @@
       fp << "private:" << endl;
       fp << "  " << cur_type << " value;" << endl;
       fp << "public:" << endl;
-      fp << "  void LoadString(const cString & str_value) {" << endl;
+      fp << "  void LoadString(const cString& str_value) {" << endl;
       fp << "    value = cStringUtil::Convert(str_value, value);" << endl;
       fp << "  }" << endl;
       fp << "  cEntry_" << cur_name << "() : cBaseConfigEntry(\""
@@ -325,185 +360,11 @@
   }  
 }
 
-cAvidaConfig* cAvidaConfig::LoadWithArgs(cStringList& argv)
-{
-  int arg_num = 1;              // Argument number being looked at.
-  
-  // Load all of the args into string objects for ease of access.
-  int argc = argv.GetSize();
-  cString* args = new cString[argc];
-  cStringIterator list_it(argv);
-  for (int i = 0; (i < argc) && (list_it.AtEnd() == false); i++) {
-    list_it.Next();
-    args[i] = list_it.Get();
-  }
-  
-  cString config_filename = "avida.cfg";
-  bool crash_if_not_found = false;
-  tDictionary<cString> sets;
-  tDictionary<cString> def_mappings;
 
-  bool flag_analyze = false;
-  bool flag_interactive = false;
-  bool flag_load = false;         cString val_load;
-  bool flag_review = false;
-  bool flag_verbosity = false;    int val_verbosity;
-  bool flag_seed = false;         int val_seed = 0;
-  
-  // Then scan through and process the rest of the args.
-  while (arg_num < argc) {
-    cString cur_arg = args[arg_num];
-    
-    // Test against the possible inputs.
-
-    // Print out a list of all possibel actions (was events).
-    if (cur_arg == "-e" || cur_arg == "-events" || cur_arg == "-actions") {
-      cout << endl << "Supported Actions:" << endl;
-      cout << cDriverManager::GetActionLibrary()->DescribeAll() << endl;
-      exit(0);
-    }
-
-    // Review configuration options, listing those non-default.
-    else if (cur_arg == "-review" || cur_arg == "-r") {
-      flag_review = true;
-    }
-    
-    else if (cur_arg == "--help" || cur_arg == "-help" || cur_arg == "-h") {
-      cout << "Options:"<<endl
-	   << "  -a[nalyze]            Process analyze.cfg instead of normal "
-               << "run." << endl
-	   << "  -c[onfig] <filename>  Set config file to be <filename>"<<endl
-     << "  -def <name> <value>   Define config include variables" << endl
-	   << "  -e; -actions          Print a list of all known actions"<< endl
-	   << "  -h[elp]               Help on options (this listing)"<<endl
-	   << "  -i[nteractive]        Run analyze mode interactively" << endl
-	   << "  -l[oad] <filename>    Load a clone file" << endl
-	   << "  -r[eview]             Review avida.cfg settings." << endl
-	   << "  -s[eed] <value>       Set random seed to <value>" << endl
-	   << "  -set <name> <value>   Override values in avida.cfg" << endl
-	   << "  -v[ersion]            Prints the version number" << endl
-	   << "  -v0 -v1 -v2 -v3 -v4   Set output verbosity to 0..4" << endl
-	   << endl;
-      
-      exit(0);
-    }
-    else if (cur_arg == "-seed" || cur_arg == "-s") {
-      if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
-        cerr << "Error: Must include a number as the random seed!" << endl;
-        exit(0);
-      } else {
-        arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-        val_seed = cur_arg.AsInt();
-      }
-      flag_seed = true;
-    } else if (cur_arg == "-analyze" || cur_arg == "-a") {
-      flag_analyze = true;
-    } else if (cur_arg == "-interactive" || cur_arg == "-i") {
-      flag_interactive = true;
-    } else if (cur_arg == "-load" || cur_arg == "-l") {
-      if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
-        cerr << "Error: Must include a filename to load from." << endl;
-        exit(0);
-      } else {
-        arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-        val_load = cur_arg;
-      }
-      flag_load = true;
-    } else if (cur_arg == "-version" || cur_arg == "-v") {
-      // We've already showed version info, so just quit.
-      exit(0);
-    } else if (cur_arg.Substring(0, 2) == "-v") {
-      val_verbosity = cur_arg.Substring(2, cur_arg.GetSize() - 2).AsInt();
-      flag_verbosity = true;
-    } else if (cur_arg == "-set") {
-      if (arg_num + 1 == argc || arg_num + 2 == argc) {
-        cerr << "'-set' option must be followed by name and value" << endl;
-        exit(0);
-      }
-      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-      cString name(cur_arg);
-      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-      cString value(cur_arg);
-      sets.Add(name, value);
-    } else if (cur_arg == "-def") {
-      if (arg_num + 1 == argc || arg_num + 2 == argc) {
-        cerr << "'-def' option must be followed by name and value" << endl;
-        exit(0);
-      }
-      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-      cString name(cur_arg);
-      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-      cString value(cur_arg);
-      def_mappings.Add(name, value);
-    } else if (cur_arg == "-c" || cur_arg == "-config") {
-      if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
-        cerr << "Error: Filename for configuration must be specified." << endl;
-        exit(0);
-      }
-      arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-      config_filename = cur_arg;
-      crash_if_not_found = true;
-    } else {
-      cerr << "Error: Unknown Option '" << args[arg_num] << "'" << endl
-      << "Type: \"" << args[0] << " -h\" for a full option list." << endl;
-      exit(0);
-    }
-    
-    arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
-  }
-  
-  // Create Config object, load with values from configuration file
-  cAvidaConfig* cfg = new cAvidaConfig();
-  cfg->Load(config_filename, def_mappings, crash_if_not_found);
-  
-  
-  if (flag_analyze) if (cfg->ANALYZE_MODE.Get() < 1) cfg->ANALYZE_MODE.Set(1);
-  if (flag_interactive) if (cfg->ANALYZE_MODE.Get() < 2) cfg->ANALYZE_MODE.Set(2);
-  if (flag_load) cfg->CLONE_FILE.Set(val_load);
-  if (flag_seed) cfg->RANDOM_SEED.Set(val_seed);
-  if (flag_verbosity) cfg->VERBOSITY.Set(val_verbosity);
-
-  
-  // Loop through all groups, then all entries, and try to load each one.
-  tListIterator<cBaseConfigGroup> group_it(cfg->group_list);
-  cBaseConfigGroup* cur_group;
-  cString val;
-  while ((cur_group = group_it.Next()) != NULL) {
-    // Loop through entries for this group...
-    tListIterator<cBaseConfigEntry> entry_it(cur_group->GetEntryList());
-    cBaseConfigEntry* cur_entry;
-    while ((cur_entry = entry_it.Next()) != NULL) {
-      if (sets.Find(cur_entry->GetName(), val)) {
-        cur_entry->LoadString(val);
-        if (cfg->VERBOSITY.Get() > VERBOSE_NORMAL)
-          cout << "CmdLine Set: " << cur_entry->GetName() << " " << val << endl;
-      }
-    }
-  }
-
-  
-  if (flag_review) {
-    cfg->PrintReview();
-    exit(0);
-  }  
-  
-  delete [] args;
-  
-  return cfg;
-}
-cAvidaConfig* cAvidaConfig::LoadWithCmdLineArgs(int argc, char * argv[])
-{
-  cStringList sl;
-  for(int i=0; i<argc; i++){
-    sl.PushRear(argv[i]);
-  }
-  return LoadWithArgs(sl);
-}
-
 bool cAvidaConfig::Get(const cString& entry, cString& ret) const
 {
   // Loop through all groups, then all entries, searching for the specified entry.
-  tConstListIterator<cBaseConfigGroup> group_it(group_list);
+  tConstListIterator<cBaseConfigGroup> group_it(m_group_list);
   const cBaseConfigGroup* cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     // Loop through entries for this group...
@@ -522,7 +383,7 @@
 bool cAvidaConfig::Set(const cString& entry, const cString& val)
 {
   // Loop through all groups, then all entries, searching for the specified entry.
-  tListIterator<cBaseConfigGroup> group_it(group_list);
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
   cBaseConfigGroup* cur_group;
   while ((cur_group = group_it.Next()) != NULL) {
     // Loop through entries for this group...
@@ -535,5 +396,40 @@
       }
     }
   }
+  tListIterator<cBaseConfigCustomFormat> format_it(m_format_list);
+  cBaseConfigCustomFormat* cur_format;
+  while ((cur_format = format_it.Next())) {
+    tListIterator<cBaseConfigFormatEntry> entry_it(cur_format->GetEntryList());
+    cBaseConfigFormatEntry* cur_entry;
+    while ((cur_entry = entry_it.Next())) {
+      if (cur_entry->GetName() == entry) {
+        cur_entry->LoadString(val);
+        return true;
+      }
+    }
+  }
+  
   return false;
 }
+
+
+void cAvidaConfig::Set(tDictionary<cString>& sets)
+{
+  // Loop through all groups, then all entries, and try to load each one.
+  tListIterator<cBaseConfigGroup> group_it(m_group_list);
+  cBaseConfigGroup* cur_group;
+  cString val;
+  while ((cur_group = group_it.Next()) != NULL) {
+    // Loop through entries for this group...
+    tListIterator<cBaseConfigEntry> entry_it(cur_group->GetEntryList());
+    cBaseConfigEntry* cur_entry;
+    while ((cur_entry = entry_it.Next()) != NULL) {
+      if (sets.Find(cur_entry->GetName(), val)) {
+        cur_entry->LoadString(val);
+        sets.Remove(cur_entry->GetName());
+        if (VERBOSITY.Get() > VERBOSE_NORMAL)
+          cout << "CmdLine Set: " << cur_entry->GetName() << " " << val << endl;
+      }
+    }
+  }
+}

Modified: development/source/main/cAvidaConfig.h
===================================================================
--- development/source/main/cAvidaConfig.h	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/cAvidaConfig.h	2007-08-17 19:00:30 UTC (rev 1956)
@@ -34,6 +34,7 @@
 
 #include <iostream>
 
+#include "cMutex.h"
 #include "cString.h"
 #include "cStringList.h"
 #include "cStringUtil.h"
@@ -110,6 +111,24 @@
   cGroup_ ## NAME() : cBaseConfigGroup(#NAME, DESC) { ; }                  \
 } NAME                                                                     \
 
+
+
+#define CONFIG_ADD_CUSTOM_FORMAT(NAME, DESC)                               \
+class cCustomFormat_ ## NAME : public cBaseConfigCustomFormat {            \
+public:                                                                    \
+  cCustomFormat_ ## NAME() : cBaseConfigCustomFormat(#NAME, DESC) { ; }    \
+} NAME
+
+
+#define CONFIG_ADD_FORMAT_VAR(NAME, DESC)                                  \
+private:                                                                   \
+  class cFormatEntry_ ## NAME : public cBaseConfigFormatEntry {            \
+  public:                                                                  \
+    cFormatEntry_ ## NAME() : cBaseConfigFormatEntry(#NAME, DESC) { ; }    \
+  } NAME;                                                                  \
+public:                                                                    \
+
+
 class cAvidaConfig {
 #if USE_tMemTrack
   tMemTrack<cAvidaConfig> mt;
@@ -135,8 +154,8 @@
 		     const cString& _def, const cString& _desc);
     virtual ~cBaseConfigEntry() { ; }
     
-    virtual void LoadString(const cString & str_value) = 0;
-    virtual bool EqualsString(const cString & str_value) const = 0;
+    virtual void LoadString(const cString& str_value) = 0;
+    virtual bool EqualsString(const cString& str_value) const = 0;
     
     const cString& GetName() const { return config_name; }
     const cString& GetType() const { return type; }
@@ -147,7 +166,7 @@
     virtual cString AsString() const = 0;
   };
   
-  // The cBaseConfigGroup class is a bass class for objects that collect the
+  // The cBaseConfigGroup class is a base class for objects that collect the
   // configuration entries into logical groups.
   class cBaseConfigGroup {
   private:
@@ -155,7 +174,7 @@
     cString description;
     tList<cBaseConfigEntry> entry_list;
   public:
-      cBaseConfigGroup(const cString& _name, const cString& _desc)
+    cBaseConfigGroup(const cString& _name, const cString& _desc)
       : group_name(_name), description(_desc) { global_group_list.PushRear(this); }
     ~cBaseConfigGroup() { ; }
     
@@ -167,6 +186,55 @@
     void AddEntry(cBaseConfigEntry* _entry) { entry_list.PushRear(_entry); }
   };
   
+  // The cConfigCustomFormat class is a class for objects that collect the custom format configuration entries into
+  // a single named custom format.
+  class cBaseConfigFormatEntry;
+  class cBaseConfigCustomFormat {
+  private:
+    cString m_format_name;
+    cString m_description;
+    tList<cBaseConfigFormatEntry> m_entry_list;
+    cStringList m_value;
+  
+  public:
+    cBaseConfigCustomFormat(const cString& _name, const cString& _desc)
+      : m_format_name(_name), m_description(_desc) { global_format_list.PushRear(this); }
+    ~cBaseConfigCustomFormat() { ; }
+    
+    const cString& GetName() const { return m_format_name; }
+    const cString& GetDesc() const { return m_description; }
+    tList<cBaseConfigFormatEntry>& GetEntryList() { return m_entry_list; }
+    const tList<cBaseConfigFormatEntry>& GetEntryList() const { return m_entry_list; }
+    
+    void AddEntry(cBaseConfigFormatEntry* _entry) { m_entry_list.PushRear(_entry); }
+  
+    const cStringList& Get() const { return m_value; }
+    void Add(const cString& value) { m_value.PushRear(value); }
+  };
+
+  // The cConfigFormatEntry class is a bass class for all configuration entries.
+  // It is used to manage the various types of entries in a dynamic fashion.
+  class cBaseConfigFormatEntry {
+  private:
+    const cString m_name;   // Name of this setting
+    const cString m_description;   // Explaination of the use of this setting
+    cBaseConfigCustomFormat* m_format;
+    
+  public:
+    cBaseConfigFormatEntry(const cString& _name, const cString& _desc)
+      : m_name(_name), m_description(_desc), m_format(global_format_list.GetLast())
+    {
+      m_format->AddEntry(this);
+    }
+    ~cBaseConfigFormatEntry() { ; }
+    
+    void LoadString(const cString& str_value) { cString lname(m_name); m_format->Add(lname + " " + str_value); }
+    
+    const cString& GetName() const { return m_name; }
+    const cString& GetDesc() const { return m_description; }    
+  };
+  
+  
   // We need to keep track of all configuration groups and the entry objects
   // that they contain.  To do this, we create a global list of groups that
   // all groups must register themselves in.  A new entry object will always
@@ -174,19 +242,34 @@
   // things in order.  When all configuration objects are built, we then
   // transfer the list to the local cAvidaConfig object (which occurs in the
   // constructor.)
+  static cMutex global_list_mutex;
   static tList<cBaseConfigGroup> global_group_list;
-  tList<cBaseConfigGroup> group_list;
-  
+  static tList<cBaseConfigCustomFormat> global_format_list;
+  tList<cBaseConfigGroup> m_group_list;
+  tList<cBaseConfigCustomFormat> m_format_list;
+
+
 public:
-  cAvidaConfig() { group_list.Transfer(global_group_list); }  
+  cAvidaConfig()
+  {
+    m_group_list.Transfer(global_group_list);
+    m_format_list.Transfer(global_format_list);
+    global_list_mutex.Unlock();
+  }
   ~cAvidaConfig() { ; }
 
-  static cAvidaConfig* LoadWithArgs(cStringList &args);
-  static cAvidaConfig* LoadWithCmdLineArgs(int argc, char* argv[]);
-  
 #ifdef OVERRIDE_CONFIG
 #include "config_overrides.h"
 #else
+  // Since the global lists are static and shared across all threads, we need to have a lock on a mutex to prevent multiple
+  // concurrent instantiations from messing each other up.  This class should be instantiated first, locking the mutex
+  // that is then unlocked at the completion of the constructor.
+  class cGlobalListLockAcquire
+  {
+  public:
+    cGlobalListLockAcquire() { global_list_mutex.Lock(); }
+  } __ListLock;
+  
   CONFIG_ADD_GROUP(GENERAL_GROUP, "General Settings");
   CONFIG_ADD_VAR(ANALYZE_MODE, int, 0, "0 = Disabled\n1 = Enabled\n2 = Interactive");
   CONFIG_ADD_VAR(VIEW_MODE, int, 1, "Initial viewer screen");
@@ -407,6 +490,10 @@
   CONFIG_ADD_VAR(BIOMIMETIC_MOVEMENT_STEP, int, 0, "Number of cells to move Avidian on move instruction");
   CONFIG_ADD_VAR(BIOMIMETIC_K, int, 0, "Carrying capacity in number of organisms");
   
+  
+  CONFIG_ADD_CUSTOM_FORMAT(INST_SET_NEW, "Instruction Set Definition");
+  CONFIG_ADD_FORMAT_VAR(INST, "Instruction entry in the instruction set");
+  
 #endif
   
   void Load(const cString& filename, const bool& crash_if_not_found);
@@ -415,8 +502,10 @@
   void Status();
   void PrintReview();
   
+  
   bool Get(const cString& entry, cString& ret) const;
   bool Set(const cString& entry, const cString& val);
+  void Set(tDictionary<cString>& sets);
   
   void GenerateOverides();
 };

Modified: development/source/main/cEnvironment.cc
===================================================================
--- development/source/main/cEnvironment.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/cEnvironment.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -750,6 +750,9 @@
 {
   cInitFile infile(filename);
   if (!infile.WasOpened()) {
+    tConstListIterator<cString> err_it(infile.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     cerr << "Error: Failed to load environment '" << filename << "'." << endl;
     return false;
   }

Modified: development/source/main/cPopulation.cc
===================================================================
--- development/source/main/cPopulation.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/cPopulation.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -2281,6 +2281,9 @@
   
   cInitFile input_file(filename);
   if (!input_file.WasOpened()) {
+    tConstListIterator<cString> err_it(input_file.GetErrors());
+    const cString* errstr = NULL;
+    while ((errstr = err_it.Next())) cerr << "Error: " << *errstr << endl;
     cerr << "Error: Cannot load file: \"" << filename << "\"." << endl;
     exit(1);
   }

Modified: development/source/main/cWorld.cc
===================================================================
--- development/source/main/cWorld.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/main/cWorld.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -92,7 +92,7 @@
   // This must be after the HardwareManager in case REACTIONS that trigger instructions are used.
   if (!m_env->Load(m_conf->ENVIRONMENT_FILE.Get())) {
     cerr << "Error: Unable to load environment" << endl;
-    ExitAvida(-1);
+    Avida::Exit(-1);
   }
   
   // Setup Stats Object
@@ -112,7 +112,7 @@
   m_event_list = new cEventList(this);
   if (!m_event_list->LoadEventFile(m_conf->EVENT_FILE.Get())) {
     cerr << "Error: Unable to load events" << endl;
-    ExitAvida(-1);
+    Avida::Exit(-1);
   }
   
 	

Modified: development/source/platform/PlatformExpert.cc
===================================================================
--- development/source/platform/PlatformExpert.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/platform/PlatformExpert.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -47,7 +47,7 @@
     SetupFloatingPointEnvironment();
     
     // Catch Interrupt making sure to close appropriately
-    signal(SIGINT, ExitAvida);
+    signal(SIGINT, Avida::Exit);
 
     cDriverManager::Initialize();
   }

Modified: development/source/targets/avida/primitive.cc
===================================================================
--- development/source/targets/avida/primitive.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/targets/avida/primitive.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -35,10 +35,13 @@
 {
   PlatformExpert::Initialize();
   
-  printVersionBanner();
+  Avida::PrintVersionBanner();
 
   // Initialize the configuration data...
-  cWorld* world = new cWorld(cAvidaConfig::LoadWithCmdLineArgs(argc, argv));
+  cAvidaConfig* cfg = new cAvidaConfig();
+  Avida::ProcessCmdLineArgs(argc, argv, cfg);
+  
+  cWorld* world = new cWorld(cfg);
   cAvidaDriver* driver = NULL;
 
   if (world->GetConfig().ANALYZE_MODE.Get() > 0) {
@@ -52,7 +55,7 @@
   driver->Run();
 
   // Exit Nicely
-  ExitAvida(0);
+  Avida::Exit(0);
   
   return 0;
 }

Modified: development/source/targets/avida-s/main.cc
===================================================================
--- development/source/targets/avida-s/main.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/targets/avida-s/main.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -48,10 +48,10 @@
       parser->Accept(visitor);
       
       std::cout << std::endl;
-      ExitAvida(0);
+      Avida::Exit(0);
     } else {
       std::cout << "Parse Failed" << std::endl;
-      ExitAvida(1);
+      Avida::Exit(1);
     }
   } else {
     std::cerr << "error: unable to open script" << std::endl;

Modified: development/source/targets/avida-viewer/viewer.cc
===================================================================
--- development/source/targets/avida-viewer/viewer.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/targets/avida-viewer/viewer.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -39,10 +39,13 @@
 {
   PlatformExpert::Initialize();
   
-  printVersionBanner();
+  Avida::PrintVersionBanner();
   
   // Initialize the configuration data...
-  cWorld* world = new cWorld(cAvidaConfig::LoadWithCmdLineArgs(argc, argv));
+  cAvidaConfig* cfg = new cAvidaConfig();
+  Avida::ProcessCmdLineArgs(argc, argv, cfg);
+  
+  cWorld* world = new cWorld(cfg);
   cAvidaDriver* driver = NULL;
   
   if (world->GetConfig().ANALYZE_MODE.Get() > 0) {
@@ -56,7 +59,7 @@
   driver->Run();
   
   // Exit Nicely
-  ExitAvida(0);
+  Avida::Exit(0);
   
   return 0;
 }

Modified: development/source/targets/viewer-text/viewer-text.cc
===================================================================
--- development/source/targets/viewer-text/viewer-text.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/targets/viewer-text/viewer-text.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -40,10 +40,13 @@
 {
   PlatformExpert::Initialize();
   
-  printVersionBanner();
+  Avida::PrintVersionBanner();
   
   // Initialize the configuration data...
-  cWorld* world = new cWorld(cAvidaConfig::LoadWithCmdLineArgs(argc, argv));
+  cAvidaConfig* cfg = new cAvidaConfig();
+  Avida::ProcessCmdLineArgs(argc, argv, cfg);
+  
+  cWorld* world = new cWorld(cfg);
   cAvidaDriver* driver = NULL;
   
   // Test to see if we should be in analyze mode only...
@@ -54,7 +57,7 @@
   driver->Run();
   
   // Exit Nicely
-  ExitAvida(0);
+  Avida::Exit(0);
   
   return 0;
 }

Modified: development/source/tools/cInitFile.cc
===================================================================
--- development/source/tools/cInitFile.cc	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/tools/cInitFile.cc	2007-08-17 19:00:30 UTC (rev 1956)
@@ -52,7 +52,7 @@
 cInitFile::cInitFile(istream& in_stream) : m_filename("(stream)"), m_ftype("unknown")
 {
   if (in_stream.good() == false) {
-    cerr << "Bad stream sent to cInitFile::LoadStream()" << endl;
+    m_errors.PushRear(new cString("Bad stream, unable to process."));
     m_opened = false;
     return;
   }
@@ -62,16 +62,12 @@
   char cur_line[MAX_STRING_LENGTH];
   in_stream.getline(cur_line, MAX_STRING_LENGTH);
   
-  // If this file doesn't work properly, return.
-  if (!in_stream && !strlen(cur_line)) {
-    m_opened = false;
-    return;
-  }
+  if (!in_stream && !strlen(cur_line)) return;
   
   int linenum = 1;
   while (in_stream) {
-    if (cur_line[0] == '#' && cur_line[1] == '!') ProcessCommand(cur_line, lines);
-    else lines.Push(new sLine(cur_line, "(stream)", linenum));
+    if (cur_line[0] == '#' && cur_line[1] == '!') ProcessCommand(cur_line, lines, m_filename, linenum);
+    else lines.Push(new sLine(cur_line, m_filename, linenum));
     
     in_stream.getline(cur_line, MAX_STRING_LENGTH);
     linenum++;
@@ -98,7 +94,10 @@
 bool cInitFile::LoadFile(const cString& filename, tSmartArray<sLine*>& lines)
 {
   cFile file(filename);
-  if (!file.IsOpen()) return false;   // The file must be opened!
+  if (!file.IsOpen()) {
+    m_errors.PushRear(new cString(cStringUtil::Stringf("Unable to open file '%s'.", (const char*)filename)));
+    return false;   // The file must be opened!
+  }
   
   cStringList line_list;   // Create a list to load all of the lines into.
 
@@ -107,36 +106,34 @@
   while (!file.Eof() && file.ReadLine(buf)) {
     linenum++;
 
-    if (buf.GetSize() > 1 && buf[0] == '#' && buf[1] == '!') ProcessCommand(buf, lines);
-    else lines.Push(new sLine(buf, filename, linenum));
+    if (buf.GetSize() > 1 && buf[0] == '#' && buf[1] == '!') {
+      if (!ProcessCommand(buf, lines, filename, linenum)) return false;
+    } else {
+      lines.Push(new sLine(buf, filename, linenum));
+    }
   }
   file.Close();
   
-  if (linenum == 0) return false; // @DMB - should this be the case?
-  
   return true;
 }
 
 
-void cInitFile::ProcessCommand(cString cmdstr, tSmartArray<sLine*>& lines)
+bool cInitFile::ProcessCommand(cString cmdstr, tSmartArray<sLine*>& lines, const cString& filename, int linenum)
 {
   cString cmd = cmdstr.PopWord();
   
   if (cmd == "#!include") {
     cString dir = cmdstr.PopWord();
-    if (dir.GetSize() && dir[0] == '$') {
-      dir.ClipFront(1);
-      if (!m_mappings.Find(dir, dir)) {
-        // @TODO - report error
-        return;
-      }
-    }
-    LoadFile(dir, lines); // @TODO - report error
-  } else if (cmd == "#!default") {
-    cString name = cmdstr.PopWord();
-    cmdstr.Trim();
-    if (!m_mappings.HasEntry(name)) m_mappings.Add(name, cmdstr);
+    cString mapping = cmdstr.PopWord();
+    if (mapping.GetSize()) m_mappings.Find(mapping, dir);
+    bool success = LoadFile(dir, lines);
+    if (!success) m_errors.PushRear(new cString(cStringUtil::Stringf("%f:%d: Unable to process include directive.",
+                                                                     (const char*)filename, linenum)));
+    return success;
   }
+  
+  m_errors.PushRear(new cString("Unrecognized processing directive."));
+  return false;
 }
 
 
@@ -263,7 +260,8 @@
   // Search for the keyword.
   cString cur_line;
   if (Find(cur_line, name, 0) == false) {
-    cerr << "Warning: " << name << " not in '" << m_filename << "', defaulting to: " << def << endl;
+    m_errors.PushRear(new cString(cStringUtil::Stringf("%s not in '%s', defaulting to: %s",
+                                                       (const char*)name, (const char*)m_filename, (const char*)def)));
     return def;
   }
 
@@ -281,13 +279,13 @@
     if (m_lines[i]->used == false) {
       if (found == false) {
         found = true;
-        cerr << "Warning: unknown lines in input file '" << m_filename << "'" << endl;
+        m_errors.PushRear(new cString(cStringUtil::Stringf("Unknown lines in input file '%s'.", (const char*)m_filename)));
       }
-      cerr << "    " << m_lines[i]->file << ":" << m_lines[i]->line_num << ": " << m_lines[i]->line << endl;
+      m_errors.PushRear(new cString(cStringUtil::Stringf("  %s:%d: %s",
+                                                         (const char*)m_lines[i]->file, m_lines[i]->line_num,
+                                                         (const char*)m_lines[i]->line)));
     }
   }
   
-  if (found == true) cerr << endl;
-
   return found;
 }

Modified: development/source/tools/cInitFile.h
===================================================================
--- development/source/tools/cInitFile.h	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/tools/cInitFile.h	2007-08-17 19:00:30 UTC (rev 1956)
@@ -35,6 +35,9 @@
 #ifndef tDictionary_h
 #include "tDictionary.h"
 #endif
+#ifndef tList_h
+#include "tList.h"
+#endif
 #ifndef tSmartArray_h
 #include "tSmartArray.h"
 #endif
@@ -51,6 +54,7 @@
 private:
   cString m_filename;
   bool m_opened;
+  mutable tList<cString> m_errors;
   
   struct sLine {
     cString line;
@@ -71,7 +75,7 @@
   
   void InitMappings(const tDictionary<cString>& mappings);
   bool LoadFile(const cString& filename, tSmartArray<sLine*>& lines);
-  void ProcessCommand(cString cmdstr, tSmartArray<sLine*>& lines);
+  bool ProcessCommand(cString cmdstr, tSmartArray<sLine*>& lines, const cString& filename, int linenum);
   void PostProcess(tSmartArray<sLine*>& lines);
 
   
@@ -83,9 +87,15 @@
   cInitFile(const cString& filename);
   cInitFile(const cString& filename, const tDictionary<cString>& mappings);
   cInitFile(std::istream& in_stream);
-  ~cInitFile() { for (int i = 0; i < m_lines.GetSize(); i++) delete m_lines[i]; }
+  ~cInitFile()
+  {
+    for (int i = 0; i < m_lines.GetSize(); i++) delete m_lines[i];
+    cString* errstr = NULL;
+    while ((errstr = m_errors.Pop())) delete errstr;
+  }
   
   bool WasOpened() const { return m_opened; }
+  const tList<cString>& GetErrors() const { return m_errors; }
   
   void Save(const cString& in_filename = "");
   
@@ -131,6 +141,8 @@
    **/
   bool WarnUnused() const;
 
+  void MarkLineUsed(int line_id) { m_lines[line_id]->used = true; }
+
   int GetNumLines() const { return m_lines.GetSize(); }
 
   const cString& GetFiletype() { return m_ftype; }

Modified: development/source/tools/tHashTable.h
===================================================================
--- development/source/tools/tHashTable.h	2007-08-17 15:28:15 UTC (rev 1955)
+++ development/source/tools/tHashTable.h	2007-08-17 19:00:30 UTC (rev 1956)
@@ -293,7 +293,7 @@
     // Determine the bin that we are going to be using.
     const int bin = HashKey(key);
     
-    DATA_TYPE out_data = NULL;
+    DATA_TYPE out_data;
     assert(cell_array[bin] != NULL);
     list_it.Set(cell_array[bin]);
     




More information about the Avida-cvs mailing list