1 /*
2  *  util/CmdLine.cc
3  *  avida-core
4  *
5  *  Copyright 1999-2011 Michigan State University. All rights reserved.
6  *  Copyright 1993-2003 California Institute of Technology.
7  *  http://avida.devosoft.org/
8  *
9  *
10  *  This file is part of Avida.
11  *
12  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
13  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
14  *
15  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
19  *  If not, see <http://www.gnu.org/licenses/>.
20  *
21  *  Authors: David M. Bryson <david@programerror.com>
22  *
23  */
24 
25 #include "avida/util/CmdLine.h"
26 
27 #include "apto/core/FileSystem.h"
28 
29 #include "cActionLibrary.h"
30 #include "cAvidaConfig.h"
31 #include "cString.h"
32 #include "cStringIterator.h"
33 #include "cUserFeedback.h"
34 #include "tDictionary.h"
35 
36 #include <iostream>
37 #include <cstdio>
38 
39 
40 using namespace std;
41 
42 
processArgs(cStringList & argv,cAvidaConfig * cfg)43 static void processArgs(cStringList &argv, cAvidaConfig* cfg)
44 {
45   int argc = argv.GetSize();
46   int arg_num = 1;              // Argument number being looked at.
47 
48   // Load all of the args into string objects for ease of access.
49   cString* args = new cString[argc];
50   //for (int i = 0; i < argc; i++) args[i] = argv[i];
51   cStringIterator list_it(argv);
52   for (int i = 0; (i < argc) && (list_it.AtEnd() == false); i++) {
53     list_it.Next();
54     args[i] = list_it.Get();
55   }
56 
57   cString config_filename = "avida.cfg";
58   tDictionary<cString> sets;
59   tDictionary<cString> defs;
60 
61   bool flag_analyze = false;
62   bool flag_interactive = false;
63   bool flag_review = false;
64   bool flag_verbosity = false;    int val_verbosity = 0;
65   bool flag_seed = false;         int val_seed = 0;
66   bool flag_warn_default = false;
67 
68   // Then scan through and process the rest of the args.
69   while (arg_num < argc) {
70     cString cur_arg = args[arg_num];
71 
72     // Test against the possible inputs.
73 
74     // Print out a list of all possibel actions (was events).
75     if (cur_arg == "-e" || cur_arg == "-events" || cur_arg == "-actions") {
76       cout << endl << "Supported Actions:" << endl;
77       cout << cActionLibrary::GetInstance().DescribeAll() << endl;
78       exit(0);
79     }
80 
81     // Review configuration options, listing those non-default.
82     else if (cur_arg == "-review" || cur_arg == "-r") {
83       flag_review = true;
84     }
85 
86     else if (cur_arg == "--help" || cur_arg == "-help" || cur_arg == "-h") {
87       cout << "Options:"<<endl
88       << "  -a[nalyze]            Process analyze.cfg instead of normal "
89       << "run." << endl
90       << "  -c[onfig] <filename>  Set config file to be <filename>"<<endl
91       << "  -def <name> <value>   Define config include variables" << endl
92       << "  -e; -actions          Print a list of all known actions"<< endl
93       << "  -h[elp]               Help on options (this listing)"<<endl
94       << "  -i[nteractive]        Run analyze mode interactively" << endl
95       << "  -l[oad] <filename>    Load a clone file" << endl
96       << "  -r[eview]             Review avida.cfg settings." << endl
97       << "  -s[eed] <value>       Set random seed to <value>" << endl
98       << "  -set <name> <value>   Override values in avida.cfg" << endl
99       << "  -v[ersion]            Prints the version number" << endl
100       << "  -v0 -v1 -v2 -v3 -v4   Set output verbosity to 0..4" << endl
101       << "  -w[arn]               Warn when default config settings are used." << endl
102       << "  --generate-config     Generate the default configration files" << endl
103       << endl;
104 
105       exit(0);
106     }
107     else if (cur_arg == "-seed" || cur_arg == "-s") {
108       if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
109         cerr << "Error: Must include a number as the random seed!" << endl;
110         exit(0);
111       } else {
112         arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
113         val_seed = cur_arg.AsInt();
114       }
115       flag_seed = true;
116     } else if (cur_arg == "-analyze" || cur_arg == "-a") {
117       flag_analyze = true;
118     } else if (cur_arg == "-interactive" || cur_arg == "-i") {
119       flag_interactive = true;
120     } else if (cur_arg == "-warn" || cur_arg == "-w") {
121       flag_warn_default = true;
122     } else if (cur_arg == "-version" || cur_arg == "-v") {
123       // We've already showed version info, so just quit.
124       exit(0);
125     } else if (cur_arg.Substring(0, 2) == "-v") {
126       val_verbosity = cur_arg.Substring(2, cur_arg.GetSize() - 2).AsInt();
127       flag_verbosity = true;
128     } else if (cur_arg == "-set") {
129       if (arg_num + 1 == argc || arg_num + 2 == argc) {
130         cerr << "'-set' option must be followed by name and value" << endl;
131         exit(0);
132       }
133       arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
134       cString name(cur_arg);
135       arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
136       cString value(cur_arg);
137       sets.Set(name, value);
138     } else if (cur_arg == "-def") {
139       if (arg_num + 1 == argc || arg_num + 2 == argc) {
140         cerr << "'-def' option must be followed by name and value" << endl;
141         exit(0);
142       }
143       arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
144       cString name(cur_arg);
145       arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
146       cString value(cur_arg);
147       defs.Set(name, value);
148     } else if (cur_arg == "-c" || cur_arg == "-config") {
149       if (arg_num + 1 == argc || args[arg_num + 1][0] == '-') {
150         cerr << "Error: Filename for configuration must be specified." << endl;
151         exit(0);
152       }
153       arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
154       config_filename = cur_arg;
155     } else if (cur_arg == "--generate-config") {
156       cerr << "Generating default avida.cfg" << endl;
157       cfg->Print(cString(Apto::FileSystem::PathAppend(Apto::FileSystem::GetCWD(), "avida.cfg")));
158       exit(0);
159     } else {
160       cerr << "Error: Unknown Option '" << args[arg_num] << "'" << endl
161       << "Type: \"" << args[0] << " -h\" for a full option list." << endl;
162       exit(0);
163     }
164 
165     arg_num++;  if (arg_num < argc) cur_arg = args[arg_num];
166   }
167 
168   delete [] args;
169 
170   // Load configuration file
171   cUserFeedback feedback;
172   cfg->Load(config_filename, cString(Apto::FileSystem::GetCWD()), &feedback, &defs, flag_warn_default);
173   for (int i = 0; i < feedback.GetNumMessages(); i++) {
174     switch (feedback.GetMessageType(i)) {
175       case cUserFeedback::UF_ERROR:    cerr << "error: "; break;
176       case cUserFeedback::UF_WARNING:  cerr << "warning: "; break;
177       default: break;
178     };
179     cerr << feedback.GetMessage(i) << endl;
180   }
181   if (feedback.GetNumErrors()) exit(-1);
182 
183 
184   // Process Command Line Flags
185   if (flag_analyze) if (cfg->ANALYZE_MODE.Get() < 1) cfg->ANALYZE_MODE.Set(1);
186   if (flag_interactive) if (cfg->ANALYZE_MODE.Get() < 2) cfg->ANALYZE_MODE.Set(2);
187   if (flag_seed) cfg->RANDOM_SEED.Set(val_seed);
188   if (flag_verbosity) cfg->VERBOSITY.Set(val_verbosity);
189 
190   cfg->Set(sets); // Process all command line -set statements
191 
192   if (sets.GetSize()) {
193     tList<cString> keys;
194     sets.GetKeys(keys);
195     cString* keystr = NULL;
196     while ((keystr = keys.Pop())) {
197       cerr << "error: unrecognized command line configuration setting '" << *keystr << "'." << endl;
198     }
199     exit(1);
200   }
201 
202 
203   if (flag_review) {
204     cfg->PrintReview();
205     exit(0);
206   }
207 }
208 
ProcessCmdLineArgs(int argc,char * argv[],cAvidaConfig * cfg)209 void Avida::Util::ProcessCmdLineArgs(int argc, char* argv[], cAvidaConfig* cfg)
210 {
211   cStringList sl;
212   for(int i=0; i<argc; i++){
213     sl.PushRear(argv[i]);
214   }
215   processArgs(sl, cfg);
216 }
217