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