1 /*
2
3 This file is part of the Maude 2 interpreter.
4
5 Copyright 1997-2010 SRI International, Menlo Park, CA 94025, USA.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21 */
22
23 //
24 // main() function and misc functions.
25 //
26 #include "sys/param.h"
27 #ifdef ALPHA
28 #include <stropts.h>
29 #endif
30
31 // utility stuff
32 #include "macros.hh"
33 #include "vector.hh"
34 #include "tty.hh"
35
36
37 // forward declarations
38 #include "interface.hh"
39 #include "core.hh"
40 #include "higher.hh"
41 #include "freeTheory.hh"
42 #include "builtIn.hh"
43 #include "strategyLanguage.hh"
44 #include "mixfix.hh"
45
46 // interface class definitions
47 #include "term.hh"
48
49 // core class definitions
50 #include "lineNumber.hh"
51
52 // built in stuff
53 #include "randomOpSymbol.hh"
54
55 // system class definitions
56 #include "IO_Manager.hh"
57
58 // mixfix frontend definitions
59 #include "token.hh"
60 #include "userLevelRewritingContext.hh"
61 #include "fileTable.hh"
62 #include "directoryManager.hh"
63 #include "mixfixModule.hh"
64 #include "interpreter.hh"
65 #include "global.hh"
66
67 int
main(int argc,char * argv[])68 main(int argc, char* argv[])
69 {
70 //
71 // Global function declatations
72 //
73 void printBanner(ostream& s);
74 void printHelp(const char* name);
75 void printVersion();
76 void createRootBuffer(FILE* fp, bool forceInteractive);
77 bool includeFile(const string& directory, const string& fileName, bool silent, int lineNr);
78 extern Vector<char*> pendingFiles;
79 const char* isFlag(const char* arg, const char* flag);
80 bool findExecutableDirectory(string& directory, string& executable);
81 bool findPrelude(string& directory, string& fileName);
82 void checkForPending();
83
84 bool lineWrapping = true;
85 bool handleCtrlC = true;
86 bool readPrelude = true;
87 bool forceInteractive = false;
88 bool outputBanner = true;
89 int ansiColor = UNDECIDED;
90 int useTecla = UNDECIDED;
91
92 for (int i = 1; i < argc; i++)
93 {
94 char* arg = argv[i];
95 if (arg[0] == '-')
96 {
97 if (const char* s = isFlag(arg, "-xml-log="))
98 interpreter.beginXmlLog(s);
99 else if (const char* s = isFlag(arg, "-random-seed="))
100 RandomOpSymbol::setGlobalSeed(strtoul(s, 0, 0));
101 else if (strcmp(arg, "--help") == 0)
102 printHelp(argv[0]);
103 else if (strcmp(arg, "--version") == 0)
104 printVersion();
105 else if (strcmp(arg, "-no-mixfix") == 0)
106 interpreter.setPrintFlag(Interpreter::PRINT_MIXFIX, false);
107 else if (strcmp(arg, "-ansi-color") == 0)
108 ansiColor = true;
109 else if (strcmp(arg, "-no-ansi-color") == 0)
110 ansiColor = false;
111 else if (strcmp(arg, "-tecla") == 0)
112 useTecla = true;
113 else if (strcmp(arg, "-no-tecla") == 0)
114 useTecla = false;
115 else if (strcmp(arg, "-no-prelude") == 0)
116 readPrelude = false;
117 else if (strcmp(arg, "-no-banner") == 0)
118 outputBanner = false;
119 else if (strcmp(arg, "-no-advise") == 0)
120 {
121 if (!alwaysAdviseFlag)
122 globalAdvisoryFlag = false;
123 }
124 else if (strcmp(arg, "-always-advise") == 0)
125 {
126 alwaysAdviseFlag = true;
127 globalAdvisoryFlag = true;
128 }
129 else if (strcmp(arg, "-no-wrap") == 0)
130 lineWrapping = false;
131 else if (strcmp(arg, "-batch") == 0)
132 handleCtrlC = false;
133 else if (strcmp(arg, "-interactive") == 0)
134 forceInteractive = true;
135 else if (strcmp(arg, "-print-to-stderr") == 0)
136 UserLevelRewritingContext::setPrintAttributeStream(&cerr);
137 else
138 {
139 IssueWarning(LineNumber(FileTable::COMMAND_LINE) <<
140 ": unrecognised flag: " << QUOTE(arg));
141 }
142 }
143 else
144 pendingFiles.append(arg);
145 }
146
147 if (lineWrapping)
148 ioManager.setAutoWrap();
149
150 if (ansiColor == UNDECIDED)
151 {
152 //
153 // By default we allow ANSI escape codes unless
154 // environment variable TERM is set to dumb; or
155 // our standard output is not a terminal.
156 //
157 ansiColor = true;
158 const char* term = getenv("TERM");
159 if ((term != 0 && strcmp("dumb", term) == 0) ||
160 isatty(STDOUT_FILENO) == 0)
161 ansiColor = false;
162 }
163 Tty::setEscapeSequencesAllowed(ansiColor);
164
165 if (useTecla == UNDECIDED)
166 {
167 //
168 // By default we use tecla for input unless
169 // environment variable TERM is set to emacs or dumb;
170 // or our standard input is not a terminal.
171 //
172 useTecla = true;
173 const char* term = getenv("TERM");
174 if ((term != 0 && (strcmp("emacs", term) == 0 ||
175 strcmp("dumb", term) == 0)) ||
176 isatty(STDIN_FILENO) == 0)
177 useTecla = false;
178 }
179
180 //
181 // Make sure we flush cout before we output any error messages so things hit the tty in a consistent order.
182 //
183 (void) cerr.tie(&cout);
184
185 if (outputBanner)
186 printBanner(cout);
187 createRootBuffer(stdin, forceInteractive);
188 UserLevelRewritingContext::setHandlers(handleCtrlC);
189 if (useTecla)
190 ioManager.setCommandLineEditing();
191 directoryManager.initialize();
192 string executable(argv[0]);
193 findExecutableDirectory(executableDirectory, executable);
194 if (readPrelude)
195 {
196 string directory;
197 string fileName(PRELUDE_NAME);
198 if (findPrelude(directory, fileName))
199 includeFile(directory, fileName, true, FileTable::AUTOMATIC);
200 }
201 else
202 checkForPending(); // because we won't hit an EOF
203 (void) UserLevelRewritingContext::commandLoop();
204 return 0;
205 }
206
operator <<(ostream & s,const LineNumber & lineNumber)207 ostream& operator<<(ostream& s, const LineNumber& lineNumber)
208 {
209 fileTable.printLineNumber(s, lineNumber.getLineNumber());
210 return s;
211 }
212
213 const char*
isFlag(const char * arg,const char * flag)214 isFlag(const char* arg, const char* flag)
215 {
216 char f;
217 do
218 {
219 f = *flag++;
220 if (f == 0)
221 return arg;
222 }
223 while (f == *arg++);
224 return 0;
225 }
226
227 void
printHelp(const char * name)228 printHelp(const char* name)
229 {
230 cout <<
231 "Maude interpreter\n" <<
232 "Usage: " << name << " [options] [files]\n" <<
233 "Options:\n" <<
234 " --help\t\tDisplay this information\n" <<
235 " --version\t\tDisplay version number\n" <<
236 " -no-prelude\t\tDo not read in the standard prelude\n" <<
237 " -no-banner\t\tDo not output banner on startup\n" <<
238 " -no-advise\t\tNo advisories on startup\n" <<
239 " -always-advise\tAlways show advisories regardless\n" <<
240 " -no-mixfix\t\tDo not use mixfix notation for output\n" <<
241 " -no-wrap\t\tDo not automatic line wrapping for output\n" <<
242 " -ansi-color\t\tUse ANSI control sequences\n" <<
243 " -no-ansi-color\tDo not use ANSI control sequences\n" <<
244 " -tecla\t\tUse tecla command line editing\n" <<
245 " -no-tecla\t\tDo not use tecla command line editing\n" <<
246 " -batch\t\tRun in batch mode\n" <<
247 " -interactive\t\tRun in interactive mode\n" <<
248 " -print-to-stderr\tPrint attribute should use stderr rather than stdout\n" <<
249 " -random-seed=<int>\tSet seed for random number generator\n" <<
250 " -xml-log=<filename>\tSet file in which to produce an xml log\n" <<
251 "\n" <<
252 "Send bug reports to: " << PACKAGE_BUGREPORT << endl;
253 exit(0);
254 }
255
256 void
printVersion()257 printVersion()
258 {
259 cout << PACKAGE_VERSION << endl;
260 exit(0);
261 }
262
263 bool
findExecutableDirectory(string & directory,string & executable)264 findExecutableDirectory(string& directory, string& executable)
265 {
266 string::size_type p = executable.rfind('/');
267 if (p == string::npos)
268 return directoryManager.searchPath("PATH", directory, executable, X_OK);
269 else
270 {
271 directoryManager.realPath(executable.substr(0, p), directory);
272 return directoryManager.checkAccess(directory, executable, X_OK);
273 }
274 }
275
276 bool
findPrelude(string & directory,string & fileName)277 findPrelude(string& directory, string& fileName)
278 {
279 if (directoryManager.searchPath(MAUDE_LIB, directory, fileName, R_OK))
280 return true;
281 if (!(executableDirectory.empty()) &&
282 directoryManager.checkAccess(executableDirectory, fileName, R_OK))
283 {
284 directory = executableDirectory;
285 return true;
286 }
287 if (directoryManager.checkAccess(MAUDE_DATADIR, fileName, R_OK))
288 {
289 directory = MAUDE_DATADIR;
290 return true;
291 }
292 if (directoryManager.checkAccess(".", fileName, R_OK))
293 {
294 directory = ".";
295 return true;
296 }
297 IssueWarning(LineNumber(FileTable::AUTOMATIC) <<
298 ": unable to locate file: " << QUOTE(fileName));
299 return false;
300 }
301